接上文: Windows 消息循环(1) - 概览

win32/MFC/WinForm/WPF 都依靠消息循环驱动,让程序跑起来。

本文介绍 WPF 中是如何使用消息循环来驱动程序的。

4 消息循环在 WPF 中的应用

4.1 引入

只听说过 Dispatcher ,哪里来的消息循环?

先瞧一眼 WPF 启动运行堆栈:

可以发现 PushFrameImpl 这个方法。

去看其源码,就发现了熟悉的消息循环 :

可以理解为:Dispatcher 对消息循环的操作进行了“封装” 。

那,Dispatcher 是谁?

4.2 Dispatchcer

Provides services for managing the queue of work items for a thread.

提供用于管理线程工作项队列的服务。

大部分WPF对象,都是 DispatcherObject。这意味着,可以在 DispatcherObject 中(如 Window 中),

使用 this.Dispatchcer 获取到 Dispatchcer 。

一般我们会通过三种方式获取 Dispatchcer :

// App.Current.Dispatcher;(Application.Current.Dispatcher)
var dispatcher1 = App.Current.Dispatcher; // CurrentDispatcher;
var dispatcher2 = System.Windows.Threading.Dispatcher.CurrentDispatcher; // System.Windows.Threading.DispatcherObject.Dispatcher;
var dispatcher3 = this.Dispatcher;

可分为两类:

  • 当前线程的 Dispatcher:

    System.Windows.Threading.Dispatcher.CurrentDispatcher;

  • 创建对应对象的 Dispatcher:

    App.Current.Dispatcher;

    DispatcherObject.Dispatcher;

可参见:

Why not Dispather.CurrentDispatcher - haungtengxiao

Dispatcher 和线程是什么关系?

  • Dispatcher 属于线程(与线程一一对应)。
  • WPF的对象在获取this.Dispatcher属性时,不同对象取的都是同一个Dispatcher实例。(因为都是同一个UI线程创建的。)
  • 在默认的 WPF UI线程中: App.Current.Dispatcher = DispatcherObject.Dispatcher

所有的线程(UI线程,普通线程)都有 Dispatcher 吗?

是的。

在所有线程中,调用 System.Windows.Threading.Dispatcher.CurrentDispatcher

都会得到一个属于这个线程的 Dispatcher 对象。(不用的时候不会创建)

所以:如果你想在一个后台线程中,使用 Dispatcher.CurrentDispatcher.Invoke

将操作封送到 UI 线程,是做不到的。因为这时候获取到的 Dispatcher 不是UI线程的 Dispatcher, 而是当前线程自己的 Dispatcher。

4.3 Dispatcher 如何实现跨线程的调用。

最常使用 Dispatcher 的创建就是,在后台线程更新 UI ,那 Dispatcher 是如何做到的呢。

当你调用

Application.Current.Dispatcher.Invoke(() =>
{
SendMessageBtn.Content = "更新按钮";
});

时,Dispatcher 究竟做了什么,把操作转移到 UI 线程上去了。

关于 Invoke,InvokeSync,BeginInvoke 的区别,参见:

深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) - walterlv

  1. 将调用的Delegate和优先级包装成一个DispatcherOperation放入Dispatcher维护的优先级队列当中,这个Queue是按DispatcherPriority排序的,总是高优先级的DispatcherOperation先被处理。

  2. 往当前线程的消息队列当中Post一个名为MsgProcessQueue的Message。(这个消息是WPF自己定义的。)这个消息被Post到消息队列之前,还要设置MSG.Handle,这个Handle就是Window 1#的Handle。指定Handle是为了在消息循环Dispatch消息的时候,指定哪个窗口的 WndProc 处理这个消息。

  3. 消息循环读取消息。

  4. 系统根据获取消息的Handle,发现跟Window1#的Handle相同,那么这个消息派发到Window1#的窗口过程,让其处理。

  5. 在窗口过程中,优先级队列当中取一个DispatcherOperation。

  6. 执行DispatcherOperation.Invoke方法,Invoke方法的核心就是调用DispatcherOperation构造时传入的Delegate,也就是Dispatcher.BeginInvoke传入的Delegate。最终这个Foo()方法就被执行了。

4.4 回顾

  • WPF 底层仍然靠信息循环来驱动。
  • Dispatcher 使用消息循环来实现跨进程的委托调用。
  • Dispatcher 属于线程,需要理解当前拿到的 Dispatcher 到底是哪个 Dispatcher 。

参考资料:

Windows 消息机制浅析 - bitbit - 博客园

SendMessage、PostMessage原理-大白菜-51CTO博客

WPF的消息机制(一)- 让应用程序动起来 - 葡萄城技术团队 - 博客园

WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口 - 葡萄城技术团队 - 博客园

WPF的消息机制(三)- WPF内部的5个窗口之处理激活和关闭的消息窗口以及系统资源通知窗口 - 葡萄城技术团队 - 博客园

Why not Dispather.CurrentDispatcher - haungtengxiao

深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) - walterlv

Tutorial: Getting Started

Windows 消息循环(2) - WPF中的消息循环的更多相关文章

  1. php中的for循环和js中的for循环

    php中的for循环 循环100个0 for ($i=0;$i<=100;$i++){ $pnums.='0'.","; } js中的for循环,循环31个相同的数.循环日期 ...

  2. 在WPF中处理Windows消息

    在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 ...

  3. 安卓中的消息循环机制Handler及Looper详解

    我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handl ...

  4. 消息队列一:为什么需要消息队列(MQ)?

    为什么会需要消息队列(MQ)? #################################################################################### ...

  5. RabbitMQ消息队列(二)-RabbitMQ消息队列架构与基本概念

    没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. RabbitMQ架构 说是架构其实更像是应用场景下的架构(自己画的有点丑,勿嫌弃) 从图中 ...

  6. MQ消息机制如何确认消费了消息?

    消息队列如何保证消息能百分百成功被消费 目前常用的消息队列有很多种,如RabbitMQ,ActiveMQ,Kafka...下面以RabbitMQ为例来讲如何保证消息队列中的信息能百分百被消费掉. 其中 ...

  7. 【转】深入Windows内核——C++中的消息机制

    上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图  Win32 ...

  8. TMsgThread, TCommThread -- 在delphi线程中实现消息循环

    http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...

  9. Chrome中的消息循环

    主要是自己做个学习笔记吧,我经验也不是很丰富,以前学习多线程的时候就感觉写多线程程序很麻烦.主要是线程之间要通信,要切线程,要同步,各种麻烦.我本身的工作经历决定了也没有太多的工作经验,所以chrom ...

随机推荐

  1. OpenCV---模糊操作

    推文:图像平滑处理(归一化块滤波.高斯滤波.中值滤波.双边滤波) 推文:图像的平滑与滤波 模糊操作 三种模糊操作方式 均值模糊 中值模糊 自定义模糊(可以实现上面两种模糊方式) 原理: 图像处理:基础 ...

  2. 2017北京国庆刷题Day4 afternoon

    期望得分:100+100+0=200 实际得分:5+0+0=5 每加入一个数,x的因数位置++ 注意:根号x枚举时,如果x是完全平方数,根号x会重复累计2次,要减去 考场上没减,5分 /(ㄒoㄒ)/~ ...

  3. windows下启动mysql服务的命令行启动和手动启动方法

    1.图形界面下启动mysql服务. 在图形界面下启动mysql服务的步骤如下: (1)打开控制面板->管理工具->服务,如下图所示: 可以看到Mysql服务目前的状态是未启动(未写已启动的 ...

  4. 爬虫实战--使用Selenium模拟浏览器抓取淘宝商品美食信息

    from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exce ...

  5. Android稳定性测试工具Monkey的使用

    综述    Monkey是一个命令行工具,它可以运行在我们的模拟器或者设备当中.它可以发送一些伪随机的用户事件流,例如点击.触摸.手势等.我们能够使用Monkey工具来对我们所开发的应用进行压力测试. ...

  6. cin循环输入控制问题

    之前写一个简单的输入节点值自动生成链表的测试程序,发现cin的输入控制好像在VC++6.0和VS2010中不一样,特此记录. 现在有以下代码: vector<int> ivec; int ...

  7. Linux端口占用

    1.netstat netstat -anp | grep 23232 Sample: [root@BICServer 0825]# netstat -anp | grep 23232 tcp 0 0 ...

  8. 大数据系列之分布式数据库HBase-0.9.8安装及增删改查实践

    若查看HBase-1.2.4版本内容及demo代码详见 大数据系列之分布式数据库HBase-1.2.4+Zookeeper 安装及增删改查实践 1. 环境准备: 1.需要在Hadoop启动正常情况下安 ...

  9. 【bzoj4293】【PA2015】Siano

    如题,首先可以考虑相对大小是不变的. 那么先sort,之后每次在线段树上二分即可. #include<bits/stdc++.h> typedef long long ll; using ...

  10. 部署weblogic 12c的几点收获

    最近刚编写完weblogic12c的部署脚本,这里将过程中的几点收获进行记录: 1.windows下编写的脚本在linux环境下运行需要dos2unix进行格式转换 2.weblogic安装环境检测需 ...