在上一篇文章 深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) 中我们发现 Dispatcher.Invoke
方法内部是靠 Dispatcher.PushFrame
来确保“不阻塞地等待”的。然而它是怎么做到“不阻塞地等待”的呢?
阅读本文将更深入地了解 Dispatcher 的工作机制。
本文是深入了解 WPF Dispatcher 的工作原理系列文章的一部分:
Dispatcher.PushFrame 是什么?
如果说上一篇文章 深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) 中的 Invoke
算是偏冷门的写法,那 ShowDialog
总该写过吧?有没有好奇过为什么写 ShowDialog
的地方可以等新开的窗口返回之后继续执行呢?
var w = new FooWindow();
w.ShowDialog();
Debug.WriteLine(w.Bar);
看来我们这次有必要再扒开 Dispatcher.PushFrame
的源码看一看了。不过在看之前,我们先看一看 Windows Forms 里面 DoEvents
的实现,这将有助于增加我们对源码的理解。
DoEvents
Windows Forms 里面的 DoEvents
允许你在执行耗时 UI 操作的过程中插入一段 UI 的渲染过程,使得你的界面看起来并没有停止响应。
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
首先我们需要拿出本文一开始的结论——调用 Dispatcher.PushFrame
可以在不阻塞 UI 线程的情况下等待。
在此基础之上,我们仔细分析此源码的原理,发现是这样的: