Windows 消息循环(2) - WPF中的消息循环
接上文: 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
将调用的Delegate和优先级包装成一个DispatcherOperation放入Dispatcher维护的优先级队列当中,这个Queue是按DispatcherPriority排序的,总是高优先级的DispatcherOperation先被处理。
往当前线程的消息队列当中Post一个名为MsgProcessQueue的Message。(这个消息是WPF自己定义的。)这个消息被Post到消息队列之前,还要设置MSG.Handle,这个Handle就是Window 1#的Handle。指定Handle是为了在消息循环Dispatch消息的时候,指定哪个窗口的 WndProc 处理这个消息。
消息循环读取消息。
系统根据获取消息的Handle,发现跟Window1#的Handle相同,那么这个消息派发到Window1#的窗口过程,让其处理。
在窗口过程中,优先级队列当中取一个DispatcherOperation。
执行DispatcherOperation.Invoke方法,Invoke方法的核心就是调用DispatcherOperation构造时传入的Delegate,也就是Dispatcher.BeginInvoke传入的Delegate。最终这个Foo()方法就被执行了。
4.4 回顾
- WPF 底层仍然靠信息循环来驱动。
- Dispatcher 使用消息循环来实现跨进程的委托调用。
- Dispatcher 属于线程,需要理解当前拿到的 Dispatcher 到底是哪个 Dispatcher 。
参考资料:
SendMessage、PostMessage原理-大白菜-51CTO博客
WPF的消息机制(一)- 让应用程序动起来 - 葡萄城技术团队 - 博客园
WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口 - 葡萄城技术团队 - 博客园
WPF的消息机制(三)- WPF内部的5个窗口之处理激活和关闭的消息窗口以及系统资源通知窗口 - 葡萄城技术团队 - 博客园
Why not Dispather.CurrentDispatcher - haungtengxiao
深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) - walterlv
Windows 消息循环(2) - WPF中的消息循环的更多相关文章
- php中的for循环和js中的for循环
php中的for循环 循环100个0 for ($i=0;$i<=100;$i++){ $pnums.='0'.","; } js中的for循环,循环31个相同的数.循环日期 ...
- 在WPF中处理Windows消息
在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 ...
- 安卓中的消息循环机制Handler及Looper详解
我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handl ...
- 消息队列一:为什么需要消息队列(MQ)?
为什么会需要消息队列(MQ)? #################################################################################### ...
- RabbitMQ消息队列(二)-RabbitMQ消息队列架构与基本概念
没错我还是没有讲怎么安装和写一个HelloWord,不过快了,这一章我们先了解下RabbitMQ的基本概念. RabbitMQ架构 说是架构其实更像是应用场景下的架构(自己画的有点丑,勿嫌弃) 从图中 ...
- MQ消息机制如何确认消费了消息?
消息队列如何保证消息能百分百成功被消费 目前常用的消息队列有很多种,如RabbitMQ,ActiveMQ,Kafka...下面以RabbitMQ为例来讲如何保证消息队列中的信息能百分百被消费掉. 其中 ...
- 【转】深入Windows内核——C++中的消息机制
上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图 Win32 ...
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环
http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...
- Chrome中的消息循环
主要是自己做个学习笔记吧,我经验也不是很丰富,以前学习多线程的时候就感觉写多线程程序很麻烦.主要是线程之间要通信,要切线程,要同步,各种麻烦.我本身的工作经历决定了也没有太多的工作经验,所以chrom ...
随机推荐
- 使用$http.post()提交数据后台接收不到
传参方式是request payload,参数格式是json,而并非用的是form传参,所以在后台用接收form数据的方式接收参数就接收不到了. POST表单请求提交时,使用的Content-Type ...
- ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——数据库的设计(一)
快一年没写博客了,这段时间感觉好迷茫,写点博客,记录一下自己的成长过程,希望对大家也有帮助 先上图 一个用户可以有多个角色,一个用户可以属于多个部门,这些都可以控制到权限,有时特殊要求,同样的部门和角 ...
- HDU6127 简单几何 暴力二分
LINK 题意:给出n个点,每个点有个权值,可以和任意另外一点构成线段,值为权值积.现问过原点的直线中交所有线段的权值和的最大值,注意直线必不经过点. 思路:直线可以将点集分为两侧,此时的权值为两侧点 ...
- web开发之Servlet 三
昨天我们学习了Servlet的运行过程和生命周期,那么今天我们学习下Servlet中非常重要的两个类:ServletConfig ServletContext 我们可以看到,与顶层Servlet主动 ...
- 【BZOJ】2134: 单选错位 期望DP
[题意]有n道题,第i道题有ai个选项.把第i道题的正确答案填到第i+1道题上(n填到1),问期望做对几道题.n<=10^7. [算法]期望DP [题解]正确答案的随机分布不受某道题填到后面是否 ...
- Function.prototype.bind 简介
bind可以解决两种问题: 1. 可以改变一个函数的 this 指向 2. 可以实现偏函数等高阶功能 本文暂且讨论第一个功能 USE CASE var foo = { x: 3 } var bar = ...
- docker之构建redis-cluster集群
下载和编译redis安装包 参考:https://www.cnblogs.com/cwp-bg/p/8094914.html # 从官方网站下载安装包,注意,当前在哪个目录下执行命令,下载的包将在哪个 ...
- Git学习笔记3 git revert
我们难免会因为种种原因执行一些错误的commit / push,git提供了revert命令帮助程序员修复这样的错误. 举个例子,下图是git commit 的历史记录 git revert 命令会通 ...
- Elasticsearch5.0 安装问题集锦【转】
转自 Elasticsearch5.0 安装问题集锦 - 代码&优雅着&生活 - 博客园http://www.cnblogs.com/sloveling/p/elasticsearch ...
- 5.Longest Palindromic Substring---dp
题目链接:https://leetcode.com/problems/longest-palindromic-substring/description/ 题目大意:找出最长回文子字符串(连续). 法 ...