🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
DispatcherObject,Dispatcher,Thread之间的关系 我们都知道WPF中的控件类都是从System.Windows.Threading.DispatcherObject继承而来, 而DispatcherObject又在构造时与当前线程的Dispatcher关联起来,CurrentDispatcher如果为null则会主动new一个Dispatcher并且在构造时和当前创建它的线程关联起来了。因此整个链为DispatcherObject <- Dispatcher <- Thread. 具体我们一起看看反编译的红色代码: public abstract class DispatcherObject {   private Dispatcher _dispatcher;   [EditorBrowsable(EditorBrowsableState.Advanced)]   public Dispatcher Dispatcher   {     get     {       return this ._dispatcher;     }   }   protected DispatcherObject()   {     base .\u002Ector();     this ._dispatcher = Dispatcher.CurrentDispatcher;   }    ........................................................ } public sealed class Dispatcher {     public static Dispatcher CurrentDispatcher    {     get     {       return Dispatcher.FromThread(Thread.CurrentThread) ?? new Dispatcher();     }    }   private Dispatcher()   {    .............................     Dispatcher._tlsDispatcher = this ;     this ._dispatcherThread = Thread.CurrentThread;    .............................   }    .............................. } 这样设计的原则就保证:界面元素只有被创建它的线程访问 Dispatcher中Invoke,BeginInvoke和Win32中SendMessage,PostMessage的关系 上面我们提到wpf的界面元素只有被创建它的线程来访问,如果我们想在后台或者其他线程里该怎么办? 答案就是利用Dispatcher的Invoke和BeginInvoke,作用就是把委托放到界面元素关联的Dispatcher里的工作项里,然后此Dispatcher关联的线程进行执行。 所不同的是Invoke是在关联的线程里同步执行委托, 而BeginInvoke是在关联的线程里异步执行委托。 做过Win32或者MFC编程的童鞋们都知道win32中有SendMessage和PostMessage类似的概念,这些概念有什么内在关系呢? 其实Dispatcher的Invoke和BeginInvoke都是调用Win32的PostMessage传递窗体句柄和消息号,反编译代码如下:   private bool RequestForegroundProcessing()   {     if (this._postedProcessingType >= 2)       return true;     if (this._postedProcessingType == 1)       SafeNativeMethods.KillTimer(new HandleRef((object) this, this._window.Value.Handle), 1);     this._postedProcessingType = 2;     return MS.Win32.UnsafeNativeMethods.TryPostMessage(new HandleRef((object) this, this._window.Value.Handle), Dispatcher._msgProcessQueue, IntPtr.Zero, IntPtr.Zero);   } 只不过Invoke在PostMessage后调用了内部返回值DispatcherOperation的wait方法,在执行结束后才返回。反编译代码如下:     DispatcherOperation dispatcherOperation = this.BeginInvokeImpl(priority, method, args, isSingleParameter);       if (dispatcherOperation != null)       {         int num = (int) dispatcherOperation.Wait(timeout);         if (dispatcherOperation.Status == DispatcherOperationStatus.Completed)           obj = dispatcherOperation.Result;         else if (dispatcherOperation.Status == DispatcherOperationStatus.Aborted)           obj = (object) null;         else           dispatcherOperation.Abort();       } WPF的消息泵和Win32的消息泵之间的关系 WPF的窗体程序都必须隐式或者显式调用[Application.Run()](http://msdn.microsoft.com/en-us/library/ms597010(v=vs.110).aspx)来初始化WPF窗体。当Application.Run()调用时, 会在其内部调用Dispatcher.Run()方法。最终会在PushFrame()方法内初始化消息泵。 具体为:Application.Run() -> Dispatcher.Run() -> Dispatcher.PushFrame() -> Dispatcher.PushFrameImpl() private void PushFrameImpl(DispatcherFrame frame)   {     MSG msg = new MSG();     ++this._frameDepth;     try     {       SynchronizationContext current = SynchronizationContext.Current;       bool flag = current != this._dispatcherSynchronizationContext;       try       {         if (flag)           SynchronizationContext.SetSynchronizationContext((SynchronizationContext) this._dispatcherSynchronizationContext);         while (frame.Continue && this.GetMessage(ref msg, IntPtr.Zero, 0, 0))           this.TranslateAndDispatchMessage(ref msg);         if (this._frameDepth != 1 || !this._hasShutdownStarted)           return;         this.ShutdownImpl();       }       finally       {         if (flag)           SynchronizationContext.SetSynchronizationContext(current);       }     }     finally     {       --this._frameDepth;       if (this._frameDepth == 0)         this._exitAllFrames = false;     }   } Ok,从上述反编译的代码可以看到,WPF还是通过Dispatcher内部实现了传统的Win32消息循环, 如GetMessage,TranslateMessage,DispatchMessage。 下面是win32消息泵的实现, 大家可以对比下: BOOL bRet; while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0) {    if (bRet == -1)    {        // handle the error and possibly exit    }    else    {        TranslateMessage(&msg);        DispatchMessage(&msg);    } }