漫长的背景过程令人耳目一新ui wpf

时间:2013-03-29 07:21:11

标签: c# wpf multithreading async-await

我有长时间的搜索操作,定期更新UI(找到出现 - >更新用户界面)

我试图通过多种方式实现它:

  1. 异步/ AWAIT

    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. BackgroundWorker的

    我想使用它,但我不想只使用.ReportProgress()

  3. 访问UI
  4. 调用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)));
            }
        }
    
  5. 完成线程后写入所有数据的所有方法。 是否有任何方法可以运行后台任务,通过阻止ui来定期更新UI而不会减慢程序速度?

2 个答案:

答案 0 :(得分:3)

最好是将“工人”逻辑与“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(...));
  }
}

答案 1 :(得分:0)

我认为在这种情况下,最好是使用绑定。使用new collection synchronization,您可以执行从其他线程添加到绑定ObservableCollection<T>的操作。

如果这对您的目的不够,只要您在另一个线程上产生一些结果,就可以使用Progress<T>在UI线程上执行操作(但顾名思义,Progress是主要用于进度报告)。

如果不适合,您可以使用TPL Dataflow。您将为UI调度程序设置一个ActionBlock<T>并设置TaskScheduler。您的工作线程会将生成的项目发送到块,块将在UI线程上处理它们。