众所周知的,WPF 中多数对象都继承自 DispatcherObject
,而 DispatcherObject
带给这些对象一个特点:不能跨线程访问。
不过,WPF 中依然存在一些例外。本文将介绍 WPF 那些可跨线程访问的 DispatcherObject
,如何充分利用这个特点提高应用程序的性能,以及如何自己编写这样的 DispatcherObject
。
要了解什么样的 DispatcherObject
可以跨线程访问,需要知道 WPF 是如何限制对象的跨线程访问的。
DispatcherObject
类有一个 Dispatcher
属性,它长下面这样:
public Dispatcher Dispatcher
{get{// This property urn _dispatcher;}
}
属性在 Dispatcher
的构造函数中被赋值:
protected DispatcherObject()
{_dispatcher = Dispatcher.CurrentDispatcher;
}
DispatcherObject
提供了两种验证 Dispatcher
的方法,CheckAccess
和 VerifyAccess
;他们内部的实现是调用 Dispatcher
类型的 CheckAccess
和 VerifyAccess
方法。
CheckAccess
用于检查调用线程对此对象是否有访问权,如果有访问权,则返回 true
,否则返回 false
。而 VerifyAccess
也是用于检查调用线程对此对象是否有访问权,如果没有访问权会抛出异常。
你可以阅读这两个方法的代码来了解其实现原理。每个方法只有短短的一两行而已,非常容易理解。
/// <summary>
/// Checks that the calling thread has access to this object.
/// </summary>
/// <remarks>
/// Only the dispatcher thread may access DispatcherObjects.
/// <p/>
/// This method is public so that any thread can probe to
/// see if it has access to the DispatcherObject.
/// </remarks>
/// <returns>
/// True if the calling thread has access to this object.
/// </returns>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public bool CheckAccess()
{return Thread == Thread.CurrentThread;
}/// <summary>
/// Verifies that the calling thread has access to this object.
/// </summary>
/// <remarks>
/// Only the dispatcher thread may access DispatcherObjects.
/// <p/>
/// This method is public so that derived classes can probe to
/// see if the calling thread has access to itself.
/// </remarks>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void VerifyAccess()
{if(!CheckAccess()){throw new InvalidOperationException(SR.Get(SRID.VerifyAccess));}
}
需要说明的是,只有调用这两个方法才会对线程的访问权限进行检查。如果你写一个类继承自 DispatcherObject
而在你的属性和方法中不直接或间接调用 VerifyAccess
,那么这是不受线程访问限制的。
只不过,WPF 封装的大多对象和属性都调用了 VerifyAccess
(例如依赖项属性),所以很大程度上限制了 WPF UI 的线程访问权限。
Dispatcher
属性的获取实际上就是在拿 _dispatcher
字段的值。于是我们现在仔细寻找 _dispatcher
的所有赋值代码,只有三处,就是下面这三个方法:
Dispatcher
;DetachFromDispatcher
,会赋值为 null
;MakeSentinel
,会赋值为另一个线程的 Dispatcher
的值(即一个线程创建,但由另一个线程来使用)。/// <summary>
/// Instantiate this object associated with the current Dispatcher.
/// </summary>
protected DispatcherObject()
{_dispatcher = Dispatcher.CurrentDispatcher;
}// This method allows certain derived classes to break the dispatcher affinity
// of our objects.
[FriendAccessAllowed] // Built into Base, also used by Framework.
internal void DetachFromDispatcher()
{_dispatcher = null;
}// Make this object a "sentinel" - it can be used in equality tests, but should
本文发布于:2024-02-02 02:54:03,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170681565240932.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |