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

  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

原文地址:https://www.cnblogs.com/jasongrass/p/10423243.html

时间: 2024-11-06 07:45:42

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

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

php中的for循环 循环100个0 for ($i=0;$i<=100;$i++){ $pnums.='0'.","; } js中的for循环,循环31个相同的数.循环日期时间 var list=[]; for(var i= 0;i < 31;i++){ list.push(620); }//日期时间 var list = []; for (var i = 1; i <= 31; i++) { list.push('2017.01.' + i); }

在WPF中处理Windows消息

在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 WPF中处理消息首先要获取窗口句柄,创建HwndSource对象 通过HwndSource对象添加消息处理回调函数. 此外 WPF中没有Handle属性,不能直接获得窗口的句柄 可以在构造函数中指定消息进行消息处理的回调函数,也可以在资源初始化后指定,在很多地方都可以指定. 以下是在资源初始化后指

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

我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handler机制来完成该功能,即当子线程中耗时操作完成后,在子线程中通过Handler向主线程发送消息,在主线程中的Handler的handleMessage方法中处理接受到的消息.这就是安卓中的消息机制,安卓中的消息机制主要是指Handler的运行机制,但是Handler的运行需要底层的MessageQu

现代IM系统中的消息系统架构

前言IM全称是『Instant Messaging』,中文名是即时通讯.在这个高度信息化的移动互联网时代,生活中IM类产品已经成为必备品,比较有名的如钉钉.微信.QQ等以IM为核心功能的产品.当然目前微信已经成长为一个生态型产品,但其核心功能还是IM.还有一些非以IM系统为核心的应用,最典型的如一些在线游戏.社交应用,IM也是其重要的功能模块.可以说,IM系统已经是任何一个带有社交属性的应用需要具备的基础功能,网络上对于这类系统的设计与实现的讨论也越来越多. IM系统在互联网初期即存在,其基础技

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

为什么会需要消息队列(MQ)? ########################################################################################## 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误.通过使用消息队列,我们可以异步处理请求,从而

转载 [WPF][C#]在WPF中内嵌WindowsForm控件-使用WindowsFormsControlLibrary

[WPF][C#]在WPF中内嵌WindowsForm控件-使用WindowsFormsControlLibrary 在[WPF][C#]在WPF中内嵌WindowsForm控件一文中为各位介绍了直接在WPF中使用XAML来嵌入Windows Form控件的作法,不过不是每个人都喜欢写XAML,而且有时候会需要把已经存在的Windows Form应用程序嵌入到WPF中,所以这次就来跟大家介绍怎么使用参考dll档的方式,把dll中的Windows Form加到WPF中. 都说了要使用Windows

如何保障消息中间件 100% 消息投递成功?如何保证消息幂等性?

一.前言 二.分析问题 三.持久化 四.confirm机制 五.消息提前持久化 + 定时任务 六.幂等含义 6.1.为什么要有幂等这种场景? 6.2.乐观锁方案 6.3.唯一ID + 指纹码 6.4.Redis原子操作 <Java 2019 超神之路> <Dubbo 实现原理与源码解析 —— 精品合集> <Spring 实现原理与源码解析 —— 精品合集> <MyBatis 实现原理与源码解析 —— 精品合集> <Spring MVC 实现原理与源码解

从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第一讲 WPF中 windows消息机制

谈到桌面应用程序,我们第一反应就是它的消息机制是怎么处理的,那么我们就先聊聊这个windows消息机制 谈起“消息机制”这个词,我们都会想到Windows的消息机制,系统将键盘鼠标的行为包装成一个Windows Message,然后系统主动将这些Windows Message派发给特定的窗口,实际上消息是被Post到特定窗口所在线程的消息队列,应用程序的消息循环再不断的从消息队列当中获取消息,然后再派发给特定窗口类的窗口过程来处理,在窗口过程中完成一次用户交互. 其实,WPF的底层也是基于Win

深入Windows内核——C++中的消息机制

<编程思想之消息机制>一文中我们讲了消息的相关概念和消息机制的模拟,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果如下: 图 2 :效果图 Win32Test.h #pragma once #include <windows.h> #include <atltypes.h> #include <tchar.h> //资源ID #define ID_BUTTO