WPF 应用程序从两个线程开始:

一个用于处理呈现
一个用于管理 UI
呈现线程有效地隐藏在后台运行,而UI线程则接收输入、处理事件、绘制屏幕以及运行应用程序代码。
大多数应用程序都使用一个 UI 线程,但在某些情况下,最好使用多个线程。我们将在后面举例说明这一点。

UI 线程对一个名为 Dispatcher 的对象内的工作项进行排队。

Dispatcher基于优先级选择工作项,并运行每一个工作项,直到完成。每个UI线程都必须至少有一个Dispatcher,并且每个 Dispatcher 都只能在一个线程中执行工作项。

要构建响应速度快、且用户友好的应用程序,诀窍是减小工作项,以最大限度地提高Dispatcher吞吐量。这样,工作项将永远不会因为在Dispatcher队列中等待处理而失效。输入与响应之间的任何可察觉的延迟都会使用户不快。

那么,WPF应用程序应如何处理大型操作呢?如果您的代码涉及大型计算,或者需要查询某台远程服务器上的数据库,应怎么办呢?通常的办法是在单独的线程中处理大型操作,而专门让UI线程来负责处理Dispatcher队列中的工作项。当大型操作完成时,可以将结果报告给 UI 线程来显示。

一直以来,Windows只允许创建UI元素的线程访问这些元素。这意味着负责某项长时间运行任务的后台线程无法更新已完成的文本框。Windows 这样做是为了确保 UI 组件的完整性。如果列表框的内容在绘制过程中被后台线程更新,那么该列表框看上去将会很奇怪。

WPF 使用一种内置互斥机制来强制执行这种协调。WPF 中的大多数类都派生自 DispatcherObject。DispatcherObject 在构造时存储对链接到当前所运行线程的 Dispatcher 的引用。实际上,DispatcherObject与创建它的线程关联。

在程序执行过程中,DispatcherObject 可以调用它的公共 VerifyAccess 方法。

VerifyAccess 检查与当前线程关联的 Dispatcher,并将它与构造过程中存储的 Dispatcher 引用进行比较。

如果两者不匹配,VerifyAccess将引发异常。VerifyAccess 用于在每个属于 DispatcherObject 的方法的开头调用。

如果只有一个线程可以修改 UI,那么后台线程如何与用户交互呢?

后台线程可以请求 UI 线程代表它执行操作。这是通过向 UI 线程的 Dispatcher 注册工作项来完成的。

Dispatcher 类提供两个注册工作项的方法:Invoke 和 BeginInvoke。
这两个方法均调度一个委托来执行。
Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。
BeginInvoke 是异步的,将立即返回。

Dispatcher 按优先级对其队列中的元素进行排序。向 Dispatcher 队列中添加元素时可指定 10 个级别。
这些优先级在 DispatcherPriority 枚举中维护。

DispatchPriority 优先级别

优先级

说明

Invalid

这是一个无效的优先级。

Inactive

工作项目已排队但未处理。

SystemIdle

仅当系统空闲时才将工作项目调度到 UI 线程。这是实际得到处理的项目的最低优先级。

ApplicationIdle

仅当应用程序本身空闲时才将工作项目调度到 UI 线程。

ContextIdle

仅在优先级更高的工作项目得到处理后才将工作项目调度到 UI 线程。

Background

在所有布局、呈现和输入项目都得到处理后才将工作项目调度到 UI 线程。

Input

以与用户输入相同的优先级将工作项目调度到 UI 线程。

Loaded

在所有布局和呈现都完成后才将工作项目调度到 UI 线程。

Render

以与呈现引擎相同的优先级将工作项目调度到 UI 线程。

DataBind

以与数据绑定相同的优先级将工作项目调度到 UI 线程。

Normal

以正常优先级将工作项目调度到 UI 线程。这是调度大多数应用程序工作项目时的优先级。

Send

以最高优先级将工作项目调度到 UI 线程。

第1种用 Task类. 推荐用这个办法


public void 工作_Task()
{
Dispatcher x = Dispatcher.CurrentDispatcher;//取得当前工作线程
//另开线程工作
Task<int> 计数 = new Task<int>(() => { return 计数方法(); });
计数.ContinueWith(工作完毕后方法);//工作完毕后执行的方法
计数.Start();//开始工作 }
public void工作完毕后方法(Task<int> 参数)
{
if (参数.IsCompleted) //正常工作完毕
{
var 结果 = 参数.Result; //取得结果
//处理结果.
//本方法非界面线程.如果需要在界面线程操作,需要转移到界面线程
}
} int c;
public int 计数方法()
{
return c++;
}

第2种方法用线程.


public void 工作_Thread()
{
Dispatcher x = Dispatcher.CurrentDispatcher;//取得当前工作线程
//另开线程工作
System.Threading.ThreadStart start = delegate()
{
//工作函数
Func<string> fu = new Func<string>(() => { return ""; });//工作函数
var 工作结果 = fu();//开始工作 //异步更新界面
x.BeginInvoke(new Action(() =>
{
//在界面线程操作 可以使用 工作结果
}), DispatcherPriority.Normal); 
};
new System.Threading.Thread(start).Start(); //启动线程
}

第3种方法用 BackgroundWorker.

这种方法介绍的比较多了.就不说了.


BackgroundWorker 后台线程;
public void线程初始化()
{
后台线程 = new BackgroundWorker();
后台线程.WorkerSupportsCancellation = true; //可以取消
后台线程.DoWork += new DoWorkEventHandler(后台线程_DoWork);
后台线程.RunWorkerCompleted += new RunWorkerCompletedEventHandler(后台线程_RunWorkerCompleted); 
}
public void 启动后台线程()
{
后台线程.RunWorkerAsync();
} void 后台线程_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//工作完毕的方法
} void 后台线程_DoWork(object sender, DoWorkEventArgs e)
{
//工作方法
}

WPF 线程 Dispatcher的更多相关文章

  1. 【WPF】Dispatcher及线程操作

    WPF 应用程序启动后,会有两个线程: 1. 一个是用来处理UI呈现(处理UI的请求,比如输入和展现等操作). 2. 一个用来管理 UI的 (对UI元素及整个UI进行管理). 像Winform一样,W ...

  2. WPF 线程:使用调度程序构建反应速度更快的应用程序

    原文:WPF 线程:使用调度程序构建反应速度更快的应用程序 作者:Shawn Wildermuth 原文:http://msdn.microsoft.com/msdnmag/issues/07/10/ ...

  3. WPF线程(Step1)——Dispatcher

    使用WPF开发时经常会遇上自己建立的线程需要更新界面UI内容,从而导致的跨线程问题. 异常内容: 异常类型:System.InvalidOperationException 异常描述: "S ...

  4. WPF中Dispatcher未捕获异常之处理

    在UI线程中 在APP.XAML中定义 DispatcherUnhandledException事件 在工作线程中 PageMain.GetInstance().Dispatcher.Invoke(( ...

  5. wpf 线程

    一.线程概述:[引用MSDN] 通常,WPF 应用程序从两个线程开始:一个用于处理呈现,一个用于管理 UI.呈现线程有效地隐藏在后台运行,而 UI 线程则接收输入.处理事件.绘制屏幕以及运行应用程序代 ...

  6. WPF线程获取UI线程

    WPF中只能是UI线程才可以改变UI控件相关,当采用多线程工作时,可用以下代码获取 UI线程进行操作: App.Current.Dispatcher.Invoke((Action)delegate() ...

  7. WPF线程中获取控件的值和给控件赋值

    WPF中使用线程操作控件,按平常的操作方法操作的话会报异常:调用线程无法访问此对象,因为另一个线程拥有该对象.所以我们要使用Dispatcher类的BeginInvoke()与Invoke()方法.B ...

  8. wpf 的dispatcher

    wpf项目中后台代码调用界面控件时,会提示进程调用的错误. private Thread JxThread = null;  //定义线程 private DataLoading.Loading nL ...

  9. WPF基础:Dispatcher介绍

    Disaptcher作用 不管是WinForm应用程序还是WPF应用程序,实际上都是一个进程,一个进程可以包含多个线程,其中有一个是主线程,其余的是子线程.在WPF或WinForm应用程序中,主线程负 ...

随机推荐

  1. PHP操作MySQL数据库5个步骤

    PHP操作MySQL数据库一般可分为5个步骤:1.连接MySQL数据库服务器:2.选择数据库:3.执行SQL语句:4.关闭结果集:5断开与MySQL数据库服务器连接. 1.用mysql_connect ...

  2. 在基于vue的webpack脚手架开发中使用了代理转发,结果浏览器发出的请求中不带cookie导致登录时总是session失效怎么办?

    环境:            有2个业务接口需要转发到82的服务器上:     ../user/getCode.do     ../user/doLogin.do 现象:          使用上述的 ...

  3. ios9适配系列教程——ios9新变化

    Demo1_iOS9网络适配_改用更安全的HTTPS iOS9把所有的http请求都改为https了:iOS9系统发送的网络请求将统一使用TLS 1.2 SSL.采用TLS 1.2 协议,目的是 强制 ...

  4. C#进阶系列——MEF实现设计上的“松耦合”(二)

    前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级 ...

  5. 某CRM项目招投标工作的感悟

    最近参与了某公司的CRM项目招标工作, 由于此项目涉及到的二级单位比较多,以及项目金额比较大,所以此招标工作从准备到宣布中标一直持续了大概3个月时间,中间过程发生了一些颇有意思的事情,因为保密的原因无 ...

  6. 82 fsck-检查与修复 Linux 档案系统

    Linux fsck命令用于 检查与修复 Linux 档案系统,可以同时检查一个或多个 Linux 档案系统. 语法 fsck [-sACVRP] [-t fstype] [--] [fsck-opt ...

  7. php根据地址的经纬度查询周围的城市例子

    目前的工作是需要对用户的一些数据进行分析,每个用户都有若干条记录,每条记录中有用户的一个位置,是用经度和纬度表示的.还有一个给定的数据库,存储的是一些已知地点以及他们的经纬度,内有43W多条的数据.现 ...

  8. Hibernate批量处理海量数据的方法

    本文实例讲述了Hibernate批量处理海量数据的方法.分享给大家供大家参考,具体如下: Hibernate批量处理海量其实从性能上考虑,它是很不可取的,浪费了很大的内存.从它的机制上讲,Hibern ...

  9. bzoj1584

    1584: [Usaco2009 Mar]Cleaning Up 打扫卫生 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 467  Solved: 31 ...

  10. Mysql 命令大全

    1.连接Mysql 格式: mysql -h主机地址 -u用户名 -p用户密码1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root - ...