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);
    }
}

聊聊WPF中的Dispatcher的更多相关文章

  1. 聊聊WPF中字体的设置

    1. 今天帮同事调试一个字体的bug:TextBox中的中文显示大小不一致, 比如包含"杰","热". 原因是WPF针对点阵字体需要指定特定字体才能正确渲染, ...

  2. WPF:浅析Dispatcher

    本人文笔差.还是直接上代码吧.(本文假设你对WPF中的Dispatcher有一定的了解) 你觉得下面的代码可以正常执行吗? private void Button_Click(object sende ...

  3. WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object)

    原文 WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object) 众所周知的,WPF 中多数对象都继承自 Dispatch ...

  4. WPF 的 Application.Current.Dispatcher 中,Dispatcher 属性一定不会为 null

    原文:WPF 的 Application.Current.Dispatcher 中,Dispatcher 属性一定不会为 null 在 WPF 程序中,可能会存在 Application.Curren ...

  5. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  6. MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信

    MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...

  7. 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?

    源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...

  8. WPF线程(Step1)——Dispatcher

    使用WPF开发时经常会遇上自己建立的线程需要更新界面UI内容,从而导致的跨线程问题. 异常内容: 异常类型:System.InvalidOperationException 异常描述: "S ...

  9. WPF中Timer与DispatcherTimer类的区别

    前几天在WPF中写了一个轨迹回放的功能,我想稍微做过类似项目的,都晓得采用一个时间控件或者时间对象作为调度器,我在这么做的时候,出现了问题,于是将程序中的Timer换成了DispatchTimer,然 ...

随机推荐

  1. 【Head First Servlets and JSP】笔记3:Servlet的生命周期

    1.servlet的存在就是要为客户服务.servlet的任务就是得到一个用户的请求,再发回一些响应. 请求可能很复杂,也可能很简单,例如,“为我的购物车结账”,这个请求携带了一些重要的数据,你必须知 ...

  2. 3D立方体图片切换动画

    在线演示 本地下载

  3. 父元素设置overflow,绝对定位的子元素会被隐藏或一起滚动

    一般情况: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <met ...

  4. .babelrc参数小解

    .babelrc是用来设置转码规则和插件的,这种文件在window上无法直接创建,也无法在HBuilder中创建,甚至无法查看,但可以在sublime text中创建.查看并编辑. 当我们使用es6语 ...

  5. css异步加载

    <link rel="preload" href="mystyles.css" as="style" onload="thi ...

  6. Python 元组Tuple概念和操作

    # 元组概念:有序的不可变的元素集合 # 和列表的区别就是, 元组元素不能修改 # 定义 # 一个元素的写法 # (666,) t = (666,) #正确写法 t = (666) #错误写法,括号当 ...

  7. 【P2158】仪仗队&欧拉函数详解

    来一道数论题吧. 这个题一眼看上去思路明确,应该是数论,但是推导公式的时候却出了问题,根本看不出来有什么规律.看了马佬题解明白了这么个规律貌似叫做欧拉函数,于是就去百度学习了一下这东西. 欧拉函数的含 ...

  8. 解决可以Ping通ip地址,但Ping不通域名的思路

    在正常的网络故障处理中,ping命令是大家经常用到的,出现ping通ip地址,但ping域名是出现超时情况,一般是由于TCP/IP协议中的“DNS设置”不正确,请检查其中的配置,或者更换其他可用的DN ...

  9. mini6410基于linux2.6.36内核通过NFS启动根文件系统总结(一搭建开发环境——建立NFS服务器)

    http://blog.csdn.net/yinjiabin/article/details/7489030 建立 nfs 服务器 在嵌入式 linux 开发的时候,常常需要使用 nfs 以方便程序的 ...

  10. Android Studio2.3中简单配置,释放C盘空间

    重新安装了一下android studio,由于占用了太多的C盘空间.记录一下,在网上收集到的studio中两个主要占用C盘空间的文件,我们将它移除C盘. 原博地址: http://blog.csdn ...