在WPF中,相当于Windows窗体中的Suspend / ResumeLayout()和BackgroundWorker()
时间:2020-03-05 18:58:46 来源:igfitidea点击:
如果我在后面的代码中使用函数,并且希望实现在状态栏中显示"正在加载...",则以下内容是有道理的,但是从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中处理此基本问题的最佳实践是什么?
解决方案
回答
使此工作最简单的方法是将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);
回答
在阅读Shawn Wildermuth的WPF线程文章:使用Dispatcher构建更响应的应用程序。
我遇到以下问题,该问题表明我们可以像在WindowsForms中一样使用Background Worker。认为:
BackgroundWorker Now that you have a sense of how the Dispatcher works, you might be surprised to know that you will not find use for it in most cases. In Windows Forms 2.0, Microsoft introduced a class for non-UI thread handling to simplify the development model for user interface developers. This class is called the BackgroundWorker. Figure 7 shows typical usage of the BackgroundWorker class. Figure 7 Using a BackgroundWorker in WPF 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"; } } The BackgroundWorker component works well with WPF because underneath the covers it uses the AsyncOperationManager class, which in turn uses the SynchronizationContext class to deal with synchronization. In Windows Forms, the AsyncOperationManager hands off a WindowsFormsSynchronizationContext class that derives from the SynchronizationContext class. Likewise, in ASP.NET it works with a different derivation of SynchronizationContext called AspNetSynchronizationContext. These SynchronizationContext-derived classes know how to handle the cross-thread synchronization of method invocation. In WPF, this model is extended with a DispatcherSynchronizationContext class. By using BackgroundWorker, the Dispatcher is being employed automatically to invoke cross-thread method calls. The good news is that since you are probably already familiar with this common pattern, you can continue using BackgroundWorker in your new WPF projects.
回答
最好和最简单:
using(var d = Dispatcher.DisableProcessing()) { /* your work... Use dispacher.begininvoke... */ }
或者
IDisposable d; Try { d = Dispatcher.DisableProcessing(); /* your work... Use dispacher.begininvoke... */ } Finally { d.Dispose(); }