今天有时间了,继续《编写高质量代码改善程序的157个建议》的阅读,当我阅读到建议87的时候,里面的一些代码示例和文中所说的不一致了,是不是我现在用的是NetFramework 4.0的缘故,已经把一些问题修复了,今天把问题写下来,告诉大家文中有些小问题需要修复一下。

WPF和WinForm窗体应用程序都有一个要求,那就是UI元素(Button,Label,Textbox控件等)必须由创建它的那个线程来更新。WinForm这方面的限制并不是很严格,所以像下面这样的代码,在Winform中的大部分情况下都可以运行:

private void buttonStartAsync_Click(object sender,EventArgs e)
{
Task t=new Task(()=>{
while(true)
{
label1.Text=DateTime.Now.ToString();
Thread.Sleep();
}
});
t.ContinueWith((task)=>{
try
{
task.Wait();
}
catch(AggregateException ex)
{
Foreach(Exception item in ex.InnerExceptions)
{
MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}",item.GetType(),Environment.NewLine,item.Source,Environment.NewLine,item.Message));
}
}
},TaskContinuationOptions.OnlyOnFauled);
t.Start();
}

我把这段代码原封不动的有敲了一遍,但是在我的测试实例里面抛出了异常,截图如下:

现在在Winform里面,我测试过的Task和多线程的操作都会报这个错误,修正这个错误很容易,可以在当前类的构造函数里面增加一下一段代码就可以:

CheckForIllegalCrossThreadCalls = false;

代码效果截图如下:

现在就好了,程序就可以正常运行了,我的文章【其他信息: 线程间操作无效: 从不是创建控件“控件名”的线程访问它。】可以解决这类问题,有详细解释。

所以说,WPF和WinForm都是严格执行主线程操作UI元素的原则。

处理多线程情况下访问UI控件还有很多方法,现在我就在罗列出一下代码:

 Task t = new Task(()=> {
2 while (true)
{
if (lblResult.InvokeRequired)
{
lblResult.BeginInvoke(new Action(() =>
{
lblResult.Text = DateTime.Now.ToString();
}));
}
else
{
lblResult.Text = DateTime.Now.ToString();
}
Thread.Sleep();
}
});
t.ContinueWith((task)=> {
try
{
task.Wait();
}
catch (AggregateException ex)
{
foreach (var item in ex.InnerExceptions)
{
MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}",item.GetType(),Environment.NewLine,item.Source,Environment.NewLine,item.Message));
}
}
},TaskContinuationOptions.OnlyOnFaulted);
t.Start();

我们可以模仿WPF处理线程的方法,增加两个新方法,这两个方法是CheckAccess和VerifyAccess,这两个方法是WPF的UI控件的最终积累DispatcherObject类型中的两个方法,代码如下:

 namespace System.Windows.Threading
{
//
// 摘要:
// 表示与 System.Windows.Threading.Dispatcher 关联的对象。
public abstract class DispatcherObject
{
//
// 摘要:
// 初始化 System.Windows.Threading.DispatcherObject 类的新实例。
protected DispatcherObject(); //
// 摘要:
// 获取与此 System.Windows.Threading.DispatcherObject 关联的 System.Windows.Threading.Dispatcher。
//
// 返回结果:
// 调度程序。
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Dispatcher Dispatcher { get; } //
// 摘要:
// 确定调用线程是否可以访问此 System.Windows.Threading.DispatcherObject。
//
// 返回结果:
// 如果调用线程可以访问此对象,则为 true;否则,为 false。
[EditorBrowsable(EditorBrowsableState.Never)]
public bool CheckAccess();
//
// 摘要:
// 强制调用线程具有此 System.Windows.Threading.DispatcherObject 的访问权限。
//
// 异常:
// T:System.InvalidOperationException:
// 调用线程不可以访问此 System.Windows.Threading.DispatcherObject。
[EditorBrowsable(EditorBrowsableState.Never)]
public void VerifyAccess();
}
}

然后,我们给自己的类型加两个类似的方法,完整代码如下:

  public partial class Form1 : Form
{
private Thread mainThread;
public Form1()
{
InitializeComponent();
} bool CheckAccess()
{
return mainThread == Thread.CurrentThread;
} void VerifyAccess()
{
if (!CheckAccess())
{
throw new InvalidOperationException("调用线程无法访问对象,因为另一个线程拥有此对象!");
}
}
private void button1_Click(object sender, EventArgs e)
{
Task t = new Task(()=> {
while (true)
{
if (!CheckAccess())
{
lblResult.BeginInvoke(new Action(() =>
{
lblResult.Text = DateTime.Now.ToString();
}));
}
else
{
lblResult.Text = DateTime.Now.ToString();
}
Thread.Sleep();
}
});
t.ContinueWith((task)=> {
try
{
task.Wait();
}
catch (AggregateException ex)
{
foreach (var item in ex.InnerExceptions)
{
MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}",item.GetType(),Environment.NewLine,item.Source,Environment.NewLine,item.Message));
}
}
},TaskContinuationOptions.OnlyOnFaulted);
t.Start();
}
}

多线程是一个很复杂的话题,我也在学习阶段和总结阶段,有不足的地方,大家多多指教。

编写高质量代码改善程序的157个建议:第87个建议之区分WPF和WinForm的线程模型的更多相关文章

  1. 编写高质量代码改善程序的157个建议:使用Dynamic来简化反射的实现

    最近有时间看点书了,把157个建议在重新看一遍,代码都调试一遍.当我看到第15个建议的时候有些出入,就记录下来,欢迎大家来探讨. 第十五条建议是,使用dynamic简化反射的使用,没有说明具体的条件. ...

  2. Java编写高质量代码改善程序的151个建议

    第一章  Java开发中通用的方法和准则 建议1:不要在常量和变量中出现易混淆的字母: (i.l.1:o.0等). 建议2:莫让常量蜕变成变量: (代码运行工程中不要改变常量值). 建议3:三元操作符 ...

  3. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  4. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  5. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  6. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  7. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  8. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  9. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

随机推荐

  1. Mysql 忘记root密码后修改root密码

    1.修改my.cnf: 在mysqld进程配置文件中添加skip-grant-tables,添加完成后记住保存. 2.重新启动MYSQL数据库: service mysqld restart 2.修改 ...

  2. Another kind of Fibonacce(矩阵快速幂,HDU3306)

    Another kind of Fibonacci Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  3. Centos5搭建vsftpd服务

    更换镜像源 由于centos5已经历史久远,内置的镜像源已经不能用.看: 因此,我手工更换了阿里云的源.(ps:我本来是想用网易的源,但不知为什么,这个源在安装vsftpd时提示http 404错误) ...

  4. iOS textfield 限制输入字数长度

    iOS textfield限制输入的最大长度 [self.textFiled addTarget:self action:@selector(textFieldDidChange:) forContr ...

  5. 【Netty】Netty传输

    一.前言 在简单学习了Netty中的组件后,接着学习Netty中数据的传输细节. 二.传输 2.1 传输示例 Netty中的数据传输都是使用的字节类型,下面通过一个实例进行说明,该实例中服务器接受请求 ...

  6. python serialread

    代码易读,不再做注释 import serial,os port = os.popen('ls /dev/ttyACM*').read()[:-1] baud = 9600 ser = serial. ...

  7. javaWeb学习总结(1)- JavaWeb开发入门

    一.基本概念 1.1.WEB开发的相关知识 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资源分为: 静态web资源( ...

  8. javaWeb学习总结(7)- 使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

  9. C. Friends

    C. Friends 题意 对于任一点,求到此点距离不超过6的节点数. 分析 第一次dfs,形成一个以 1 为根的有向树,设 down[i][j] 为以i为根节点,距离 i 点距离不超过 j 的节点数 ...

  10. 模板C++ 03图论算法 1最短路之单源最短路(SPFA)

    3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过 ...