wpf BackgroundWorker 和 Dispatcher.Invoke
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19749326/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
BackgroundWorker and Dispatcher.Invoke
提问by Unplug
Like many applications, I want to update my status text when the application is doing long computation. I've read articles about Dispatcher and BackgroundWorker. I know I definitely need to make sure the the updates happen in the UI thread. My first try was:
像许多应用程序一样,我想在应用程序进行长时间计算时更新我的状态文本。我读过关于 Dispatcher 和 BackgroundWorker 的文章。我知道我绝对需要确保更新发生在 UI 线程中。我的第一次尝试是:
MyView.UpdateStatus( "Please wait" );
LongComputation();
MyView.UpdateStatus( "Ready" );
This does not work because (I think) the LongComputation prevents the status being updated.
这不起作用,因为(我认为) LongComputation 阻止状态更新。
So I tried to do this:
所以我尝试这样做:
BackgroundWorker worker = new BackgroundWorker();
MyView.UpdateStatus( "Please wait");
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
LongComputation();
}
worker.RunWorkerAsync();
MyView.UpdateStatus( "Ready" );
I was hopping that the extra thread will give the UpdateStatus a chance to update status text. It does not work either. One of the reason is that the result of the LongComputation is displayed in a Windows Form. As soon as I put the LongComputation inside the BackgroundWorker, the result doesn't show up.
我希望额外的线程会给 UpdateStatus 一个更新状态文本的机会。它也不起作用。原因之一是 LongComputation 的结果显示在 Windows 窗体中。一旦我将 LongComputation 放入 BackgroundWorker 中,结果就不会显示出来。
So I tried a third time by using the flowing code:
所以我第三次尝试使用流动代码:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
Dispatcher.Invoke(((Action)(() => Status.Text = args.Argument as string)));
};
worker.RunWorkerAsync(newStatus);
I was hoping that putting the update in a another thread would work. But it didn't.
我希望将更新放在另一个线程中会起作用。但它没有。
What can I do to make sure that the status reflects the correct program state?
我该怎么做才能确保状态反映正确的程序状态?
回答by Jason
BackgroundWorker uses the RunWorkerCompleted and the ReportProgress events to communicate back to the main thread. RunWorkerCompleted should do what you need to do as it will get executed on the UI thread as soon as the background work is complete.
BackgroundWorker 使用 RunWorkerCompleted 和 ReportProgress 事件与主线程通信。RunWorkerCompleted 应该做你需要做的事情,因为它会在后台工作完成后立即在 UI 线程上执行。
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
LongComputation();
};
// RunWorkerCompleted will fire on the UI thread when the background process is complete
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
if (args.Error != null)
{
// an exception occurred on the background process, do some error handling
}
MyView.UpdateStatus("Ready");
};
MyView.UpdateStatus("Please wait");
worker.RunWorkerAsync();
Additionally, you can use the RunWorkerCompleted to marshall results back to the main thread using the Result property of the DoWorkerEventArgs.
此外,您可以使用 RunWorkerCompleted 使用 DoWorkerEventArgs 的 Result 属性将结果编组回主线程。
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
args.Result = LongComputation();
};
worker.rep
// RunWorkerCompleted will fire on the UI thread when the background process is complete
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
if (args.Error != null)
{
// an exception occurred on the background process, do some error handling
}
var result = args.Result;
// do something on the UI with your result
MyView.UpdateStatus("Ready");
};
Finally, you can use the ReportProgress event you update your UI at logical steps in your background process:
最后,您可以使用 ReportProgress 事件在后台进程的逻辑步骤更新您的 UI:
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
FirstHalfComputation();
// you can report a percentage back to the UI thread, or you can send
// an object payload back
int completedPercentage = 50;
object state = new SomeObject();
worker.ReportProgress(completedPercentage , state);
SecondHalfComputation();
};
worker.WorkerReportsProgress = true; // this is important, defaults to false
worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
int completedPercentage = args.ProgressPercentage;
SomeObject state = args.UserState as SomeObject
// update a progress bar or do whatever makes sense
progressBar1.Step = completedPercentage;
progressBar1.PerformStep();
};

