zoukankan      html  css  js  c++  java
  • 聊聊WPF中的Dispatcher

    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()来初始化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);
        }
    }





  • 相关阅读:
    java--保留重复排序
    java--TreeSet比较器排序
    java--去重练习
    java--HashSet
    java--集合可变参数
    spring MVC入门
    java IO详解
    spring入门
    redis详解
    maven教程
  • 原文地址:https://www.cnblogs.com/muzizongheng/p/3431379.html
Copyright © 2011-2022 走看看