15

如果我在后面代码中的函数中,并且我想实现在状态栏中显示“正在加载...”,则以下是有意义的,但正如我们从 WinForms 中知道的那样,这是一个否:

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 中处理这个基本问题的最佳实践是什么?

4

3 回答 3

35

最好和最简单的:

using(var d = Dispatcher.DisableProcessing())
{
    /* your work... Use dispacher.begininvoke... */
}

或者

IDisposable d;

try
{
    d = Dispatcher.DisableProcessing();
    /* your work... Use dispacher.begininvoke... */
} finally {
    d.Dispose();
}
于 2010-08-01T17:30:29.437 回答
1

在阅读 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 类,而后者又使用 SynchronizationContext 类来处理同步。在 Windows 窗体中,AsyncOperationManager 传递派生自 SynchronizationContext 类的 WindowsFormsSynchronizationContext 类。同样,在 ASP.NET 中,它使用 SynchronizationContext 的不同派生,称为 AspNetSynchronizationContext。这些 SynchronizationContext 派生类知道如何处理方法调用的跨线程同步。

在 WPF 中,此模型使用 DispatcherSynchronizationContext 类进行了扩展。通过使用 BackgroundWorker,Dispatcher 被自动用于调用跨线程方法调用。好消息是,由于您可能已经熟悉这种常见模式,您可以继续在新的 WPF 项目中使用 BackgroundWorker。

于 2008-09-18T00:55:59.013 回答
-1

The easiest way to get this to work is to add the LoadSettingsGridData to the dispatcher queue. If you set the operation's DispatcherPriority sufficiently low enough, the layout operations will occur, and you will be good to go.

StatusBarMessageText.Text = "Loading Configuration Settings...";
this.Dispatcher.BeginInvoke(new Action(LoadSettingsGridData), DispatcherPriority.Render);
this.Dispatcher.BeginInvoke(new Action(() => StatusBarMessageText.Text = "Done"), DispatcherPriority.Render);
于 2008-09-17T13:32:18.423 回答