使用Rx枚举所有文件

时间:2014-09-23 17:10:47

标签: c# reactive-programming

这是我尝试在文件搜索过程中使用大量文件(或来自慢速网络文件夹)进行化妆列表框时更具响应性的界面。

IDisposable observer;
IObservable<IList<FileInfo>> bufferedFiles;
ObservableCollection<object> _fileCollection = new ObservableCollection<object>();

public void EnumerateFiles(string myfolder, string filter)
{
    var syncContext = SynchronizationContext.Current;
    DirectoryInfo dir = new DirectoryInfo(myfolder);

    this.bufferedFiles =
     Observable.Buffer(dir.EnumerateFiles(filter, System.IO.SearchOption.AllDirectories)
    .ToObservable(NewThreadScheduler.Default), TimeSpan.FromSeconds(.2), 100, NewThreadScheduler.Default)
    .ObserveOn(syncContext); 

    this.observer = this.bufferedFiles.Subscribe(outputFiles);
}

private void outputFiles(IEnumerable<FileInfo> FI)
{
    foreach (var file in FI)
        _fileCollection.Add(file);
    Debug.Print(_fileCollection.Count.toString());
}

缓冲区说明如下:

  

...将可观察序列的每个元素放入已发送的缓冲区中   当它已满或已经过了一段时间时,它就会消失。

所以我希望在本地驱动器列表框中一次可以获得100个项目,而在慢速网络上,它将输出在.2秒内收集的任何缓冲区(只要它小于100次迭代)。我希望枚举在其他线程上,而观察必须显然在调度员。

问题是UI被冻结了。

1 个答案:

答案 0 :(得分:2)

Observable.Interval每隔指定的时间跨度重复一次操作。缓冲就足以实现你的愿望了。

private async Task OutputFiles(IEnumerable<object> paths) 
{ 
    foreach (var o in paths) 
    {
         await Task.Delay(1); // Delay so the UI can update the List
        _fileCollection.Add(o); 
    }

    this.observer = Observable.Buffer(
      dir.EnumerateFiles(
         myfile, 
         System.IO.SearchOption.AllDirectories, 
         true).ToObservable(Scheduler.Default), 
      TimeSpan.FromSeconds(.5),                      
      Scheduler.Default)
   .ObserveOn(syncContext)
   .Subscribe(async x => await outputFiles(x));
}