如果我在后面的代码中有一个函数,并且我想在状态栏中实现显示“正在加载...”,则以下内容是有意义的,但正如我们从WinForms中知道的那样是NoNo:
StatusBarMessageText.Text = "Loading Configuration Settings...";
LoadSettingsGridData();
StatusBarMessageText.Text = "Done";
我们现在从WinForms第1章101类开始,在整个函数完成之前,表单不会显示对用户的更改...这意味着“加载”消息将永远不会显示给用户。需要以下代码。
Form1.SuspendLayout();
StatusBarMessageText.Text = "Loading Configuration Settings...";
Form1.ResumeLayout();
LoadSettingsGridData();
Form1.SuspendLayout();
StatusBarMessageText.Text = "Done";
Form1.ResumeLayout();
在WPF中处理这个基本问题的最佳做法是什么?
答案 0 :(得分:32)
最简单:
using(var d = Dispatcher.DisableProcessing())
{
/* your work... Use dispacher.begininvoke... */
}
或者
IDisposable d;
try
{
d = Dispatcher.DisableProcessing();
/* your work... Use dispacher.begininvoke... */
} finally {
d.Dispose();
}
答案 1 :(得分:2)
阅读Shawn Wildermuth撰写的文章WPF Threads: Build More Responsive Apps With The Dispatcher。
我遇到了以下内容,其中指出您可以像使用WindowsForms一样使用后台工作程序。想象一下:
的BackgroundWorker 现在您已经了解了Dispatcher的工作原理,您可能会惊讶地发现在大多数情况下您将无法使用它。在Windows Forms 2.0中,Microsoft引入了一个非UI线程处理类,以简化用户界面开发人员的开发模型。该类称为BackgroundWorker。图7显示了BackgroundWorker类的典型用法。
图7在WPF中使用BackgroundWorker
BackgroundWorker _backgroundWorker = new BackgroundWorker(); ... // Set up the Background Worker Events _backgroundWorker.DoWork += _backgroundWorker_DoWork; backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted; // Run the Background Worker _backgroundWorker.RunWorkerAsync(5000); ... // Worker Method void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // Do something } // Completed Method void _backgroundWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { statusText.Text = "Cancelled"; } else if (e.Error != null) { statusText.Text = "Exception Thrown"; } else { statusText.Text = "Completed"; } }
BackgroundWorker组件适用于WPF,因为它在底层使用AsyncOperationManager类,而AsyncOperationManager类又使用SynchronizationContext类来处理同步。在Windows窗体中,AsyncOperationManager移除了从SynchronizationContext类派生的WindowsFormsSynchronizationContext类。同样,在ASP.NET中,它使用名为AspNetSynchronizationContext的SynchronizationContext的不同派生。这些SynchronizationContext派生类知道如何处理方法调用的跨线程同步。
在WPF中,此模型使用DispatcherSynchronizationContext类进行扩展。通过使用BackgroundWorker,Dispatcher将自动用于调用跨线程方法调用。好消息是,由于您可能已经熟悉这种常见模式,因此可以在新的WPF项目中继续使用BackgroundWorker。
答案 2 :(得分:-1)
使此工作的最简单方法是将LoadSettingsGridData添加到调度程序队列。如果将操作的DispatcherPriority设置得足够低,则会发生布局操作,您将会很高兴。
StatusBarMessageText.Text = "Loading Configuration Settings...";
this.Dispatcher.BeginInvoke(new Action(LoadSettingsGridData), DispatcherPriority.Render);
this.Dispatcher.BeginInvoke(new Action(() => StatusBarMessageText.Text = "Done"), DispatcherPriority.Render);