DispatcherObject,Dispatcher,Thread之间的关系
我们都知道WPF中的控件类都是从System.Windows.Threading.DispatcherObject继承而来, 而DispatcherObject又在构造时与当前线程的Dispatcher关联起来,CurrentDispatcher如果为null则会主动new一个Dispatcher并且在构造时和当前创建它的线程关联起来了。因此整个链为DispatcherObject <- Dispatcher <- Thread. 具体我们一起看看反编译的红色代码:
public abstract class DispatcherObject
{
private Dispatcher _dispatcher;
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Dispatcher Dispatcher
{
get
{
return this ._dispatcher;
}
}
protected DispatcherObject()
{
base .\u002Ector();
this ._dispatcher = Dispatcher.CurrentDispatcher;
}
........................................................
}
public sealed class Dispatcher
{
public static Dispatcher CurrentDispatcher
{
get
{
return Dispatcher.FromThread(Thread.CurrentThread) ?? new Dispatcher();
}
}
private Dispatcher()
{
.............................
Dispatcher._tlsDispatcher = this ;
this ._dispatcherThread = Thread.CurrentThread;
.............................
}
..............................
}
这样设计的原则就保证:界面元素只有被创建它的线程访问
Dispatcher中Invoke,BeginInvoke和Win32中SendMessage,PostMessage的关系
上面我们提到wpf的界面元素只有被创建它的线程来访问,如果我们想在后台或者其他线程里该怎么办?
答案就是利用Dispatcher的Invoke和BeginInvoke,作用就是把委托放到界面元素关联的Dispatcher里的工作项里,然后此Dispatcher关联的线程进行执行。
所不同的是Invoke是在关联的线程里同步执行委托, 而BeginInvoke是在关联的线程里异步执行委托。
做过Win32或者MFC编程的童鞋们都知道win32中有SendMessage和PostMessage类似的概念,这些概念有什么内在关系呢?
其实Dispatcher的Invoke和BeginInvoke都是调用Win32的PostMessage传递窗体句柄和消息号,反编译代码如下:
private bool RequestForegroundProcessing()
{
if (this._postedProcessingType >= 2)
return true;
if (this._postedProcessingType == 1)
SafeNativeMethods.KillTimer(new HandleRef((object) this, this._window.Value.Handle), 1);
this._postedProcessingType = 2;
return MS.Win32.UnsafeNativeMethods.TryPostMessage(new HandleRef((object) this, this._window.Value.Handle), Dispatcher._msgProcessQueue, IntPtr.Zero, IntPtr.Zero);
}
只不过Invoke在PostMessage后调用了内部返回值DispatcherOperation的wait方法,在执行结束后才返回。反编译代码如下:
DispatcherOperation dispatcherOperation = this.BeginInvokeImpl(priority, method, args, isSingleParameter);
if (dispatcherOperation != null)
{
int num = (int) dispatcherOperation.Wait(timeout);
if (dispatcherOperation.Status == DispatcherOperationStatus.Completed)
obj = dispatcherOperation.Result;
else if (dispatcherOperation.Status == DispatcherOperationStatus.Aborted)
obj = (object) null;
else
dispatcherOperation.Abort();
}
WPF的消息泵和Win32的消息泵之间的关系
WPF的窗体程序都必须隐式或者显式调用
Application.Run()来初始化WPF窗体。当Application.Run()调用时, 会在其内部调用Dispatcher.Run()方法。最终会在PushFrame()方法内初始化消息泵。
具体为:Application.Run() -> Dispatcher.Run() -> Dispatcher.PushFrame() -> Dispatcher.PushFrameImpl()
private void PushFrameImpl(DispatcherFrame frame)
{
MSG msg = new MSG();
++this._frameDepth;
try
{
SynchronizationContext current = SynchronizationContext.Current;
bool flag = current != this._dispatcherSynchronizationContext;
try
{
if (flag)
SynchronizationContext.SetSynchronizationContext((SynchronizationContext) this._dispatcherSynchronizationContext);
while (frame.Continue && this.GetMessage(ref msg, IntPtr.Zero, 0, 0))
this.TranslateAndDispatchMessage(ref msg);
if (this._frameDepth != 1 || !this._hasShutdownStarted)
return;
this.ShutdownImpl();
}
finally
{
if (flag)
SynchronizationContext.SetSynchronizationContext(current);
}
}
finally
{
--this._frameDepth;
if (this._frameDepth == 0)
this._exitAllFrames = false;
}
}
Ok,从上述反编译的代码可以看到,WPF还是通过Dispatcher内部实现了传统的Win32消息循环, 如GetMessage,TranslateMessage,DispatchMessage。
下面是win32消息泵的实现, 大家可以对比下:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
- 聊聊WPF中字体的设置
1. 今天帮同事调试一个字体的bug:TextBox中的中文显示大小不一致, 比如包含"杰","热". 原因是WPF针对点阵字体需要指定特定字体才能正确渲染, ...
- WPF:浅析Dispatcher
本人文笔差.还是直接上代码吧.(本文假设你对WPF中的Dispatcher有一定的了解) 你觉得下面的代码可以正常执行吗? private void Button_Click(object sende ...
- WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object)
原文 WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object) 众所周知的,WPF 中多数对象都继承自 Dispatch ...
- WPF 的 Application.Current.Dispatcher 中,Dispatcher 属性一定不会为 null
原文:WPF 的 Application.Current.Dispatcher 中,Dispatcher 属性一定不会为 null 在 WPF 程序中,可能会存在 Application.Curren ...
- MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息
MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...
- MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信
MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...
- 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?
源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...
- WPF线程(Step1)——Dispatcher
使用WPF开发时经常会遇上自己建立的线程需要更新界面UI内容,从而导致的跨线程问题. 异常内容: 异常类型:System.InvalidOperationException 异常描述: "S ...
- WPF中Timer与DispatcherTimer类的区别
前几天在WPF中写了一个轨迹回放的功能,我想稍微做过类似项目的,都晓得采用一个时间控件或者时间对象作为调度器,我在这么做的时候,出现了问题,于是将程序中的Timer换成了DispatchTimer,然 ...
随机推荐
- 【转载】格式化存储装置成为 Ext2/Ext3/Ext4 档案系统
格式化 用系统管理员帐户 (即 root) 身份打「mkfs -t ext2|ext3|ext4 储存装置」: mkfs -t ext3 /dev/sdb5 要格式化档案系统为 Ext2,亦可以直接使 ...
- Linux虚拟内存管理(glibc)
转:https://blog.csdn.net/tengxy_cloud/article/details/53067396 https://www.cnblogs.com/purpleraintear ...
- linux基础四----samba&&nginx
一 samba 1环境配置: a.确保linux下防火墙关闭比或开放共享目录权限 iPtables -F b.确保setlinux关闭:setenforce 0 c.配置iP 2安装软件包:yum i ...
- React Native的导入导出
1.组件的导入导出方式 问1:如何导出一个组件? export default class EIComponent extends Component{ render(){ return( <T ...
- 文件系统的特性,linux的EXT2文件系统【转】
本文转载自:https://blog.csdn.net/tongyijia/article/details/52809281 先来提出三个概念: - superblock - inode - bloc ...
- vector对象
vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,例如vector<int> 定义和初始化vector对象: vector<T> v1 ...
- RpcException:No provider available for remote service异常
出现RpcException:No provider available for remote service异常,表示没有可用的服务提供者. 解决思路: 1.检查连接的注册中心是否正确 2.到注册中 ...
- 字符串匹配算法BF和KMP总结
背景 来看一道leetcode题目: Implement strStr(). Returns the index of the first occurrence of needle in haysta ...
- 【转】服务器.htaccess 详解以及 .htaccess 参数说明
htaccess文件(或者”分布式配置文件”)提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录.作为用户,所能使用的命令受到限 ...
- BZOJ2764 [JLOI2011]基因补全
Description 在 生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对.两个碱基序列能相互 匹配,当且仅当它们等长,并 ...