接上文: 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. poi复杂excel的实现

    一:前言 最近帮一个朋友做excel的导出功能,对于我来说还是挺头疼,我看了下表格样式,对于我来说还是挺头疼的,想当年耗子刚刚出社会的时候做的第一份工作,第一份任务就是把把word转换为html,在这 ...

  2. matlab的rem()和mod()函数

    matlab的rem()和mod()函数 rem(x,y):求整除x/y的余数 mod(x,y):求模 rem(x,y)=x-y.*fix(x./y);  (fix()向0取整) mod(x,y)=x ...

  3. Javascript的执行过程详细研究

    下面我们以更形象的示例来说明JavaScript代码在页面中的执行顺序.如果说,JavaScript引擎的工作机制比较深奥是因为它属于底层行为,那么JavaScript代码执行顺序就比较形象了,因为我 ...

  4. 关于static关键字

    static用于修饰成员(成员变量,成员函数),不能修饰局部变量被修饰的变量和函数是静态的,可被多个对象共享,节省内存可以直接被类名调用++++++++++++++++++++++++++++++++ ...

  5. 如何在移动端app中应用字体图标icon fonts

    How to use icon fonts in your mobile apps 在任何APP设计中实现可图形的矢量缩放最完美的方式是使用字体图标. 移动端的设计变的越来越复杂.原因在于多样的屏幕尺 ...

  6. PHP分页类分享

    /** * 获取分页的HTML内容 * @param integer $page 当前页 * @param integer $pages 总页数 * @param string $url 跳转url地 ...

  7. php文件上传——php经典实例

     php文件上传——php经典实例 表单页 <html> <head> <title>文件上传</title> <meta charset='ut ...

  8. pycharts实现可视化

    https://blog.csdn.net/u012535605/article/details/80677791http://pyecharts.org/#/zh-cn/prepare  (中文官网 ...

  9. Django【设计】同功能不同实现模式的兼容性

    需求: 当我们采集硬件信息时,客户端可以有多种方式,具体方式取决于客户机,CMDB项目中,我们有三种方式可选,AGENT/SSH/SALT,根据客户机具体情况和“SALT>>SSH> ...

  10. 64_t3

    texlive-dice-svn28501.0-33.fc26.2.noarch.rpm 24-May-2017 15:52 36490 texlive-dichokey-doc-svn17192.0 ...