我对 Rx 有点陌生,所以如果这看起来很愚蠢或明显,请原谅......
我有一个应用程序,它在某个时间扫描选定的文件夹并递归检索所有文件,之后它需要将它们存储在数据库中。我想在该过程中显示一个进度条,同时保持 UI 响应当然。取消按钮在稍后阶段也会很好。
我已经使用 Rx 实现了这一点,如下所示:
// Get a list of all the files
var enumeratedFiles = Directory.EnumerateFiles(targetDirectory, "*.*", SearchOption.AllDirectories);
// prepare the progress bar
double value = 0;
progBar.Minimum = 0;
progBar.Maximum = enumeratedFiles.Count();
progBar.Value = value;
progBar.Height = 15;
progBar.Width = 100;
statusBar.Items.Add(progBar);
var files = enumeratedFiles.ToObservable()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOnDispatcher()
.Subscribe(x =>
{
myDataSet.myTable.AddTableRow(System.IO.Path.GetFileNameWithoutExtension(x));
value++;
},
() =>
{
myDataSetTableAdapter.Update(myDataSet.myTable);
myDataSetTableAdapter.Fill(myDataSet.myTable);
statusBar.Items.Remove(progBar);
});
但是,对于上面的示例,UI 被锁定,并且在此过程中进度条不会更新。我认为这是因为 AddTableRow 方法阻塞了线程,尽管我认为 SubscribeOn(TaskPoolScheduler) 应该在新线程上运行任务?
我也尝试了几种不同的方法,结果各不相同。例如添加一个 .Do 行:
var files = enumeratedFiles.ToObservable()
.Do(x => myDataSet.myTable.AddTableRow(System.IO.Path.GetFileNameWithoutExtension(x)))
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOnDispatcher()
.Subscribe(x =>
{
value++;
},
() =>
{
myDataSetTableAdapter.Update(myDataSet.myTable);
myDataSetTableAdapter.Fill(myDataSet.myTable);
statusBar.Items.Remove(progBar);
btnCancel.Visibility = Visibility.Collapsed;
});
这实际上显示了进度条的更新,并且 UI 没有完全锁定,而是波涛汹涌,性能下降......
我尝试使用 BackgroundWorker 来完成相同的工作,但性能比上面的 Rx 方法差得多(例如,对于 21000 个文件,Rx 方法需要几秒钟,而 BackgroundWorker 需要几分钟才能完成)。
对于进度条的 ValueProperty 方法,我也看到了 Delegates 解决了类似的问题,但如果可能的话,我真的很想使用 Rx 来解决这个问题。
我在这里遗漏了一些明显的东西吗?任何建议将不胜感激......