对于WPF程序,大家绕不开的一个概念叫做Dispatcher


  • 什么是Dispathcer

WPF程序启动后会有两个线程:UI线程和渲染线程。UI线程会将所有的任务切成小份,放入一个队列进行依次执行,而执行这些工作的object就是Dispatcher。对于WPF来说,常见的Dispatcher概念有三个Application.Current.Dispatcher,Dispather.CurrentDispatcherDispatcherObject.Dispatcher

  • 三者的区别

对于大部分的WPF类来说,它们都继承于DispatcherObject。而每个DispatcherObject都只能被创建它的DispatcherObject所操作。这种行为的实现方式就是,在每个DispatcherObject的操作之前,会调用VerifyAccess方法,检测当前线程的Dispatcher(即Dispather.CurrentDispatcher)和自身的Dispatcher(即DispatcherObject.Dispatcher)是否相同。若不相同则会抛出相应的异常。

所以可以从此了解到,Dispather.CurrentDispatcher是和当前线程相关的Dispathcer,而DispatcherObject.Dispatcher是创建这个对象的Dispathcer

那么Application.Current.Dispatcher呢?Application.Current是一个单例模式,指向的是当前WPF进程的Application实例。而Application继承于DispatcherObject,所以Application.Current.Dispatcher是一个特殊的DispatcherObject.Dispatcher

  • Why not Dispather.CurrentDispatcher

回到主题,为什么我们不推荐使用Dispather.CurrentDispatcher

事实上,大家进程使用Dispatcher的场合是在后台线程更新UI内容。因为所有的UI线程创建的DispatcherObject对象只能在UI线程操作。因此需要“告诉”UI线程的DispatcherInvoke一个操作。而此时(后台线程中)UI线程中创建的ApplicationDispatcherObjectDispatcher属性都指向UI线程的Dispatcher对象。而Dispather.CurrentDispatcher并不是。所以就会出现相应的错误。

参考链接:

  • [Threading Model Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/threading-model#threading_overview)
  • [Dispatcher Class (System.Windows.Threading) Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher?redirectedfrom=MSDN&view=netframework-4.7.2)
  • c# - WPF/threading: Dispatcher static vs Dispatcher on a control? - Stack Overflow
  • [Application Class (System.Windows) Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/api/system.windows.application?view=netframework-4.7.2)

本文会经常更新,请阅读原文: https://huangtengxiao.gitee.io/post/Why-not-Dispather.CurrentDispatcher.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://huangtengxiao.gitee.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系