3

UI を定期的に更新する長い検索操作があります (発生の検出 -> UI の更新)

私はそれを多くの方法で実現しようとしました:

  1. 非同期/待機

    public void PushButton()
    {
        await AsyncSearchAll();
    }
    
    public async Task AsyncSearchAll(SearchPanelViewModel searchPanelViewModel, SearchSettings searchSettings, CancellationToken cancellationToken)
    {
        await Task.Factory.StartNew(() =>
                                          {
                                              //searching for occurence
                                              //write it into panel
                                          }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    }
    
  2. バックグラウンドワーカー

    使用したいが、.ReportProgress() だけを使用して UI にアクセスしたくない

  3. 呼び出しを伴う単純なバックグラウンド スレッドDispatcher.BeginInvoke(()=>{//updating UI})

    /// <summary>
    ///     Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            var backgroundThread = new Thread(CountToTen)
                {
                    IsBackground = true
                };
            backgroundThread.Start();
        }
    
        private void CountToTen()
        {
            for (int i = 1; i <= 10000; i++)
            {
                var j = i;
                Dispatcher.BeginInvoke(new Action(() => Seconds.Text = j.ToString(CultureInfo.InvariantCulture)));
            }
        }
    

スレッドの完了後にすべてのデータを書き込むすべてのメソッド。UIをブロックしてプログラムを遅くすることなく、定期的にUIを更新するバックグラウンドタスクを実行する方法はありますか?

4

2 に答える 2

4

「ワーカー」ロジックを「UI 更新」ロジックから分離できることが最善です。

このようなもの:

public async Task AsyncSearchAll(SearchPanelViewModel searchPanelViewModel, SearchSettings searchSettings, CancellationToken cancellationToken)
{
  while (..)
  {
    var results = await Task.Run(() => /* search more */);
    /* update panel with results */
  }
}

しかし、実際の進行状況の更新が必要な場合は、それを行う方法もあります。

public async void PushButton()
{
  Progress<MyUpdateType> progress = new Progress<MyUpdateType>(update =>
  {
    /* update panel */
  });
  await Task.Run(() => SearchAll(..., progress));
}

public void SearchAll(SearchPanelViewModel searchPanelViewModel,
    SearchSettings searchSettings, CancellationToken cancellationToken,
    IProgress<MyUpdateType> progress)
{
  while (..)
  {
    /* search more */
    if (progress != null)
      progress.Report(new MyUpdateType(...));
  }
}
于 2013-03-29T12:22:06.353 に答える
0

このような場合は、バインディングを使用できるとよいと思います。新しいコレクションの同期を使用すると、ObservableCollection<T>別のスレッドからバインドに追加するなどのことができます。

これでは不十分な場合はProgress<T>、他のスレッドで何らかの結果が生成されるたびに、UI スレッドでアクションを実行するために を使用できます (ただし、その名前が示すように、Progress主に進行状況のレポートを目的としています)。

どちらにも当てはまらない場合は、TPL Dataflow を使用できます。UI スケジューラーに設定された 1 つのActionBlock<T>withがあります。TaskSchedulerワーカー スレッドは生成されたアイテムをブロックに送信し、ブロックはそれらを UI スレッドで処理します。

于 2013-03-29T22:00:01.063 に答える