WPF线程问题

今天看书上写的一个例子,

1  private void AddMessage(string formatString,
2            params string[] parameters)
3         {
4           Dispatcher.BeginInvoke(new Action(
5                () => WatchOutput.Items.Insert(
6                   0, string.Format(formatString, parameters))));
7 }
View Code

Dispatcher.BeginInvoke是啥玩意,为啥要这么做呢?为啥不直接用

1 WatchOutput.Items.Insert(0, string.Format(formatString, parameters));
View Code

于是就做了个实验,当用下面这个语句的时候,点击Watch按钮的时候,没有问题,但当我修改对应文件的属性时,触发事件,此时报错。

未处理InvalidOperationException“由于其他线程拥有此对象,因此调用线程无法对其进行访问。

    上网查了下,原来是线程问题,WPF应用程序一般有两个线程,一个用于处理呈现(渲染UI),一个用来管理UI。呈现线程有效地隐藏在后台进行,而UI线程则接受输入、处理事件、绘制屏幕以及运行应用程序代码。

    那为啥上面会出现这个问题呢?点击watch,没有问题,但当修改文件属性等操作时,就会出问题。这是因为有些事件处理函数,当事件被触发时,代码执行到事件处理函数里面的时候,执行代码的线程往往不是主线程,而出于对UI控件的保护,由UI进程创建的控件,其它线程是不能访问UI线程里的东西的。

通过下面能看到,执行事件时,是另外一个线程。

1)当点击Watch!按钮,触发click事件,此时的线程是主线程(UI线程)

2)当修改文件属性,触发created\changed等事件时,会创建一个新的工作线程。

注意:这里并不是所有的事件处理函数都会创建新的线程,从上面的例子就能看出来。

  

   那既然只有主线程可以修改UI ,其它线程应该如何与用户交互呢?其它线程可以请求UI线程代表他执行操作,也就是通过向dispatcher中注册工作项来完成,dispatcher提供两个注册工作项的方法:invoke(同步)和Begininvoke(异步)。

从上面的例子看到,为了能向界面中添加文本,向dispather中注册了事件(采用lamda表达式)。

  

    在我们用的系统中,也用到了Invoke:在显示next business时。在主线程中通过ParameterizedThreadStart创建一个新的进程。在这个进程中要修改界面上的内容,就只能调用invoke方法。

                       

原文地址:https://www.cnblogs.com/icbcfang/p/4398888.html