私は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がロックされており、プロセス中に進行状況バーが更新されません。これは、SubscribeOn(TaskPoolScheduler)が新しいスレッドでタスクを実行することになっていると信じていたのに、AddTableRowメソッドがスレッドをブロックしているためだと思いますか?
私もいくつかの異なるアプローチを試しましたが、結果はさまざまです。たとえば、.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を使用してこれを解決したいと思います。
ここで明らかな何かが欠けていますか?任意の提案をいただければ幸いです...