目录

WPF的消息机制(一)-让应用程序动起来

WPF的消息机制(二)-WPF内部的5个窗口

(1)隐藏消息窗口

(2)处理激活和关闭的消息的窗口和系统资源通知窗口

(3)用于用户交互的可见窗口

(4)用于UI窗口绘制的可见窗口

WPF的消息机制(三)-WPF输入事件的来源

WPF的消息机制(四)-WPF中UI的更新

WPF内部的5个窗口

对于Windows系统来说,它是一个消息系统,消息系统的核心就是窗口。对于WPF来说也是如此。那么WPF内部为什么需要窗口,又存在哪些窗口呢?

在上一篇,我们频繁的提及“线程”,“Dispatcher”其实,运行WPF应用程序所在的线程就是WPF所谓的UI线程,在Application.Run之后,调用Dispatcher.Run时会检查当前线程是否已经存在了一个Dispatcher对象,如果没有就构造一个,在这里,一个线程对应一个Dispatcher。因此,WPF的对象在获取this.Dispatcher属性时,不同对象取的都是同一个Dispatcher实例。另外,前面提到的“消息循环”,“消息队列”等都是Win32应用程序的概念,我们知道,提起这些概念,必然会跟Win32的“窗口”,“Handle”,“WndProc”之类的概念离不开,那么WPF里面究竟有没有“窗体”,“Handle”,“WndProc”呢?

我想说的是:有,还不止一个,只不过没有暴露出来,外面不需要关心这些。

通常情况下,一个WPF应用程序在运行起来的时候,后台会创建5个Win32的窗口,帮助WPF系统来处理操作系统以及应用程序内部的消息。在这5个窗口中,只有一个是可见的,可以处理输入事件与用户交互,其他4个窗口都是不可见的,帮助WPF处理来自其他方面的消息。接下来我会来介绍究竟这5个Win32的窗口如何帮助WPF处理消息,我会根据每个窗口创建的顺序来介绍。

隐藏消息窗口

创建时机:在Application的构造函数调用基类DispatcherObject的构造函数的时候,会创建一个Dispatcher对象,在Dispatcher的私有构造函数当中。

用途:实现WPF线程模型的异步调用。

谈到异步调用,相信许多人都不陌生。WinForm下,我们通常为了使一些花费较多时间的方法调用不影响UI的响应,会将这个操作分为很多步,然后使用BeginInvoke调用每一步,这样UI响应就不会被阻塞。BeginInvoke的本质是往消息队列当中PostMessage,而不是直接调用,与此同时,UI行为(MouseMove)导致系统也往消息队列当中PostMessage更新UI,但由于彼此花费的时间很短,就感觉两个消息是被同时处理似的,界面就不会觉得被阻塞了。WPF同样面临这样的问题,他是如何解决的呢?在这里Window 1#起着至关重要的作用。通过下面一副图我们来看看Window 1#在做什么事情?

WPF也是通过BeginInvoke来解决的,而Wpf的BeginInvoke是在Dispatcher上面暴露了,因为整个消息系统都是Dispatcher在协调。从上面图可以看出Dispatcher在调用BeginInvoke之后所经历的流程,最终是什么时候Foo()被真正执行的。

第一步,就是将调用的Delegate和优先级包装成一个DispatcherOperation放入Dispatcher维护的优先级队列当中,这个Queue是按DispatcherPriority排序的,总是高优先级的DispatcherOperation先被处理。关于优先级相关知识可以参考MSDN对WPF线程模型的解释。

第二步,往当前线程的消息队列当中Post一个名为MsgProcessQueue的Message。这个消息是WPF自己定义的,见Dispatcher的静态构造函数当中的

_msgProcessQueue = UnsafeNativeMethods.RegisterWindowMessage("DispatcherProcessQueue");

这个消息被Post到消息队列之前,还要设置MSG.Handle,这个Handle就是Window 1#的Handle。指定Handle是为了在消息循环Dispatch消息的时候,指定哪个窗口的WndProc(窗口过程)处理这个消息。在这里所有BeginInvoke引起的消息都是Window1#的窗口过程来处理的。

第三步,消息循环读取消息。

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

第五步,在窗口过程中,优先级队列当中取一个DispatcherOperation。

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

通过上面的六步过程,一次Dispatcher.BeginInvoke就被处理完成。而这个过程需要消息不断的流动,就必须加入消息队列,最后还要特定的窗口过程处理,而核心的东西就是这个隐藏的Window1#,他在WPF当中只负责处理异步调用,其他的消息他不关心,剩余的4个窗口在处理。这个Window1#在WPF当中被包了一层壳子,如果感兴趣,你可以去查看类型MessageOnlyHwndWrapper。

开发工具

ComponentOne Studio WPF 是专为桌面应用程序开发所准备的一整套控件包,崇尚优雅和创新,以“触控优先”为设计理念,内含轻量级高性能表格控件,和大量类型丰富的2D和3D图表控件,能使开发的应用程序更富创意。

 

WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口的更多相关文章

  1. window消息机制二

    消息机制 windows是一个消息驱动的系统,会有一个总的系统消息的队列,鼠标.键盘等等都会流入到这个队列中,同时会为每个线程维护一个消息队列(注意默认是有GUI调用的线程才有,对于没有GUI或者窗口 ...

  2. Windows 消息循环(2) - WPF中的消息循环

    接上文: Windows 消息循环(1) - 概览 win32/MFC/WinForm/WPF 都依靠消息循环驱动,让程序跑起来. 本文介绍 WPF 中是如何使用消息循环来驱动程序的. 4 消息循环在 ...

  3. WPF入门教程系列二十三——DataGrid示例(三)

    DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...

  4. C#中的WinForm的消息机制简述,及消息机制下Invoke,和BeginInvoke的使用和区别

    在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对.net事件的看法. 一.为什么Control类提供了Invoke和Begin ...

  5. Android全面解析之由浅及深Handler消息机制

    前言 很高兴遇见你~ 欢迎阅读我的文章. 关于Handler的博客可谓是俯拾皆是,而这也是一个老生常谈的话题,可见的他非常基础,也非常重要.但很多的博客,却很少有从入门开始介绍,这在我一开始学习的时候 ...

  6. CCBPM工作流引擎的消息机制与设计

    keyword:ccflowjflow 消息机制流程引擎 自己主动发送短信 发送邮件 发送消息 流程引擎微信连接 消息接口 关于ccbpm: 我们把ccflow jflow两个版本号的工作流引擎统称为 ...

  7. 第十章:Android消息机制

    Android的消息机制主要是指Handler的云心机制,Handler的运行需要底层的MessageQueue和Looper支持. Handler是Android消息机制的上层接口. 通过Handl ...

  8. 史上最详细的Android消息机制源码解析

    本人只是Android菜鸡一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 606页Android最新面试题含答案,有兴趣可以点击获取. ...

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

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

随机推荐

  1. 数据库索引------Btree索引的使用限制

    1.如果不是按照索引最左列开始查找,则无法使用索引. 比如说id+name   那么是name+id 的话  ,这个索引则无法使用. 2.使用索引时不能跳过索引中的列.   如果是id+name+ag ...

  2. 非常棒的教程记录(UML)

    这里暂且记录下看过的非常棒的博客吧! 来自 CSDN 几年前的博客专栏了,我只想说:经典实用的知识永远不会过时! http://blog.csdn.net/column/details/umlmode ...

  3. 基于 HTML5 Canvas 的 3D 压力器反序列化

    在实际应用中,我觉得能够通过操作 JSON 文件来操作 3D 上的场景变化是非常方便的一件事,尤其是在做编辑器进行拖拽图元并且在图元上产生的一系列变化的时候,都能将数据很直观地反应给我们,这边我们简单 ...

  4. AspNet Core Api Restful +Swagger 发布IIS 实现微服务之旅 (二)

    上一步我们创建好CoreApi 接下来在框架中加入 Swagger  并发布  到 IIS (1)首先点击依赖项>管理Nuget包 (2)输入 Swashbuckle.aspnetCore  比 ...

  5. Spark Shuffle模块——Suffle Read过程分析

    在阅读本文之前.请先阅读Spark Sort Based Shuffle内存分析 Spark Shuffle Read调用栈例如以下: 1. org.apache.spark.rdd.Shuffled ...

  6. habase单机版安装及基本功能演示

    本文所使用的Linux发行版本为:CentOS Linux release 7.4.1708 (Core) 准备工作 创建用户 useradd -m hadoop passwd hadoop 下载安装 ...

  7. 【 全干货 】5 分钟带你看懂 Docker !

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者丨唐文广:腾讯工程师,负责无线研发部地图测试. 导语:Docker,近两年才流行起来的超轻量级虚拟机,它可以让你轻松完成持续集成.自动交付 ...

  8. 中国版Office 365 应用程序注册

    作者:陈希章 发表于 2017年3月23日 中国版Office 365是由世纪互联进行运营的一个云服务,单纯从技术角度来看的话,它基本保持了与国际版的同步.但是由于两个版本本质上是完全独立的,其中最关 ...

  9. 解决 ASP.NET Core Hangfire 未授权(401 Unauthorized)

    相关文章:ASP.NET Core 使用 Hangfire 定时任务 ASP.NET Core Hangfire 在正式环境发布之后,如果访问 http://10.1.2.31:5000/hangfi ...

  10. Intellij IDEA 使用小结

    快捷键 核心快捷键 IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建议了键盘快捷键.在这个主题中,您可以找到最不可缺少的列表,使 IntelliJ IDEA 轻松实现第一步 ...