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. 解决Ubuntun 12.04编译Mesa10.3 WARNING: 'aclocal-1.14' is missing on your system

    安 装Mesa时,最后一个错误报“WARNING: 'aclocal-1.14' is missing on your system.”,虽然是个Warning,但是无法进行下一步make,所以必须解 ...

  2. python__Django 分页

    自定义分页的类: #!/usr/bin/env python # -*- coding: utf-8 -*- # Created by Mona on 2017/9/20 from django.ut ...

  3. Docker容器技术-基础命令

    一.基础命令 1.运行一个镜像 [root@bogon ~]# docker run debian echo "Hello World" Unable to find image ...

  4. [SCOI2013]火柴棍数字(背包)

    题目 做饭 由于越高位越好,我们先得出能组成的最高位 \(f[i][j][k]\)表示从低到高位第\(i\)位,手里拿着\(j\)根火柴,第\(i\)位是否为\(0\)所需要的最少火柴 我们转移仅需得 ...

  5. windows7 安装Apache2时出现failed to open the winNT service manager 提示

    因为电脑实在太慢了,C盘的空间所剩无几,要想再安装大一点的软件的话,可能性很小.加之系统已经好久没有重装过了,于是重新安装windows7旗舰版,系统装好后,免不了一堆软件的重装和开发环境配置,首要的 ...

  6. IIS部署PHP项目并与mysql完美结合

    在上一篇文章中,提到iis与apache共用80端口,但是发现很多问题,例如 IIS网站有支付功能,而微信支付是不支持带有端口的网址的,虽然通过apche代理,在外面看来没有端口,可是内部还是避免不了 ...

  7. webview 详解

    [原文] 1. 打开网页时不调用系统浏览器, 而是在本WebView中显示: mWebView.setWebViewClient(new WebViewClient(){ @Override publ ...

  8. Linux嵌入式 -- 内核 - 内核定时器

    1.  度量时间差 时钟中断由系统的定时硬件以周期性的时间间隔产生,这个间隔(即频率)由内核根据HZ来确定,HZ是一个与体系结构无关的常数,可配置(50-1200),在X86平台,默认值为1000(每 ...

  9. IPC 进程间通信

    linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它 ...

  10. weinre远程调试

    一: 关于weinre weinre是一款依赖于nodejs的远程调试工具,现阶段一般用到手机app上调试非常的强大 二: weinre的安装 1)  安装 nodejs以及npm 2) 安装wein ...