今天有时间了,继续《编写高质量代码改善程序的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. Hadoop2.6.1中的Reducer实现

    正在考虑怎么方便上传图片 1.Partitioner其是一个抽象类,只有一个抽象方法.其作用是对Reducer产生的中间结果进行分片,以方便将同一分组的数据交给同一个Reducer处理 2.类的继承结 ...

  2. 使用Git初始化项目

    1.在Git官网上点击New repository新建项目: 2.在本地新建一个同名文件: 3.打开git bash切换到新建的文件目录: 4.echo "# myprojectname&q ...

  3. 关于STM32在程序中间修改PWM值的总结(原创)

    首先在STM32库函数里有这样一个函数 void TIM3_PWM_Init(u16 arr,u16 psc)   若TIM3_PWM_Init(7200,100)//设置频谱7200.分频100   ...

  4. 008多对一 关联映射 --- many-to-one

    多对一 --- many-to-one 一对多 --- one-to-many 一对一 --- one-to-one 多对多 --- many-to-many 场景:用户和组:从用户角度来,多个用户属 ...

  5. 《算法4》2.1 - 插入排序算法(Insertion Sort), Python实现

    排序算法列表电梯: 选择排序算法:详见 Selection Sort 插入排序算法(Insertion Sort):非常适用于小数组和部分排序好的数组,是应用比较多的算法.详见本文 插入排序算法的语言 ...

  6. Android WebView 不支持 H5 input type="file" 解决方法

    最近因为赶项目进度,因此将本来要用原生控件实现的界面,自己做了H5并嵌入webview中.发现点击H5中 标签 不能打开android资源管理器. 通过网络搜索发现是因为 android webvie ...

  7. C语言到C++(1) - 基本变化

    说到C++和C语言的区别,大部分人都会想到面向对象和面向过程.然而这种说法并不准确.面向对象和面向过程指的是两种不同的程序设计思想,而C++与C是两种编程语言,难道C++就不能用于面向过程去解决问题吗 ...

  8. java之内部类

    最近学了java,对内部类有一点拙见,现在分享一下 所谓内部类(nested classes),即:面向对象程序设计中,可以在一个类的内部定义另一个类. 内部类不是很好理解,但说白了其实也就是一个类中 ...

  9. dedecms做好的网站怎么上传到网上?

    1.首先做好网站后把网站所有和数据库备份 dedecms  点击 系统 - 数据库备份/还原 - 全选  后---提交-----等待备份完全 备份文件在哪里:data/backupadta--- 2. ...

  10. java加密算法入门(一)-算法概念及单向加密

    说起加密,我的第一印象就是电视剧各种密码本破解解密的场景,这两天在看加密相关的东西,做下笔记以便以后查看,也提供给大家个参考. 本文是java加密的第一篇,主要讲述下消息编码Base64以及简单的消息 ...