ProgressBar从另一个线程更新

时间:2013-11-15 15:53:10

标签: c# wpf multithreading progress-bar async-await

我知道这个问题之前曾被问过100次,但我读到的所有答案对我都没有用。所以,我会试试运气再问一次。

我有SliderBar调用ValueChanged事件的方法。 在这种方法中,我做了一些需要时间的事情,我希望在这个时候用户会看到“工作”ProgressBarIsIndeterminate=true)。

不幸的是,在所有方法循环完成之前,我没有成功使ProgressBar开始工作(在UI中)。 我尝试了线程,BackgroundWorkerasync任务,但没有成功..

我做错了什么?

这是方法:

    private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e){
        WorkingBar.IsIndeterminate = true;      //change the progressBar          
        SqlAThread = new Thread(SqlAStart);     
        SqlAThread.Start();
    }

主题:

    private void SqlAStart()
    {
        ... //do some stuff
    }

3 个答案:

答案 0 :(得分:4)

Slider_ValueChanged中,您开始使用耗时的SqlAStart()方法,但是SqlAStart会立即将工作推送到UI线程(通过Dispatcher.Invoke())。因此,您的用户界面会挂起,在完成工作之前您不会看到任何ProgressBar进度。

SqlAStart中,只需执行Dispatcher.Invoke(),您需要更新进度条:

private void SqlAStart()
{
    ServerThread = new Thread(HttpSrv.listen);
    ServerThread.Start();
    ...

    this.Dispatcher.Invoke((Action)(() => {
        WorkingBar.Value = ...                
    }));

    ....
}

答案 1 :(得分:1)

使用IProgress<T>

非常容易
private async void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
  if (State.Value > 0)
  {
    var progress = new Progress<int?>(value =>
    {
      WorkingBar.IsIndeterminate = (value == null);
      if (value != null)
        WorkingBar.Value = value.Value;
    });
    await Task.Run(() => doWork(progress));
    Task.Run(SqlAStart);
  }
  ...
}

private void SqlAStart(IProgress<int?> progress)
{
  ServerTask = Task.Run(HttpSrv.listen);
  ...
}

private void doWork(IProgress<int?> progress)
{
  if (progress != null)
    progress.Report(null);
  ...
}

请注意,您(几乎)不应在现代应用程序中使用DispatcherThreadBackgroundWorker

答案 2 :(得分:0)

我请您在StackOverflow上查看我对Progress Bar update from Background worker stalling问题的回答,而不是输入整个冗长的过程。它演示了如何正确使用BackgroundWorker对象来更新ProgressBar的进度值。

您可能还想查看MSDN上的BackgroundWorker Class页面以获取更多详细信息。