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 数据流。您将有一个单独ActionBlock<T>TaskScheduler设置为 UI 调度程序。您的工作线程会将生成的项目发送到块,并且块将在 UI 线程上处理它们。

于 2013-03-29T22:00:01.063 回答