在视图使用多线程进行WPF编程的时候,新手如我一定会试过引发一个异常,大致的意思是“某个控件在线程a上创建,你不能在线程b上改动它”,例如使用ProgressBar去显示运算进度,当新建的运算线程完成,并在此线程上直接改动ProgressBar时,就会出现这种异常。
如何解决?
参考地址:http://msdn.microsoft.com/zh-cn/magazine/cc163328.aspx
所有 WPF 应用程序启动时都会加载两个重要的线程:一个用于呈现UI,另一个用于管理UI。呈现线程是一个在后台运行的隐藏线程,因此您通常面对的唯一线程就是管理UI的线程。WPF 要求将其大多数对象与该UI线程进行关联。这称之为线程关联,意味着要使用一个 WPF 对象,只能在创建它的线程上使用。在其他线程上使用它会导致引发运行时异常。
线程关联由 Dispatcher 类处理,该类即是用于 WPF 应用程序的、按优先级排列的消息循环。通常,WPF 项目有单个 Dispatcher 对象(因此有单个 UI 线程),所有用户界面工作均以其为通道。
与 典型的消息循环不同,发送到 WPF 的每个工作项目都以特定的优先级通过 Dispatcher 进行发送。这就能够按优先级对项目排序,并延迟某种类型的工作,直到系统有时间来处理它们。(例如,有些工作项目可被延迟到系统或应用程序处于空闲状态 时。) 支持项目优先顺序使 WPF 能够让某种类型的工作拥有更多的权限,因此在线程上拥有比其他工作更多的时间。
除了使用 Dispatcher 的消息循环将工作项目引导至用户界面线程之外,每个 WPF 对象也可感知对其负责的 Dispatcher(以及它由此所依赖的 UI 线程)。这意味着任何从第二个线程更新 WPF 对象的尝试均会失败。这就是 DispatcherObject 类的主要职责。
1.DispatcherObject
DispatcherObject 类有两个主要职责:提供对对象所关联的当前 Dispatcher 的访问权限,以及提供方法以检查 (CheckAccess) 和验证 (VerifyAccess) 某个线程是否有权访问对象(派生于 DispatcherObject)。
2.调度程序
Dispatcher 类提供了到 WPF 中消息泵的通道,还提供了一种机制来路由供 UI 线程处理的工作。这对满足线程关联要求是必要的,但是对通过 Dispatcher 路由的每个工作来说,UI 线程都被阻止,因此使 Dispatcher 完成的工作小而快非常重要。最好将用户界面的大块工作拆分为较小的离散块,以便 Dispatcher 执行。任何不需要在 UI 线程上完成的工作应移到其他线程上,以便在后台进行处理。
但是一定要注意,在新线程上更新界面,不能使用一下的手段
// The Work to perform on another thread
ThreadStart start = delegate()
{
// ...
// This will throw an exception
// (it's on the wrong thread)
statusText.Text = "From Other Thread";
};
// Create the thread and kick it started!
new Thread(start).Start();
ThreadStart start = delegate()
{
// ...
// This will throw an exception
// (it's on the wrong thread)
statusText.Text = "From Other Thread";
};
// Create the thread and kick it started!
new Thread(start).Start();