原文 c#中多线程访问winform控件的若干问题小结

我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题。然而我们并不能用传统方法来解决这个问题,下面我将详细的介绍。

传统方法:

    public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){Thread thread = new Thread(ThreadFuntion);thread.IsBackground = true;thread.Start();}private void ThreadFuntion(){while (true){this.textBox1.Text = DateTime.Now.ToString();Thread.Sleep(1000);}}}

运行这段代码,我们会看到系统抛出一个异常:Cross-thread operation not valid:Control 'textBox1' accessed from  a thread other than the thread it was created on . 这是因为.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性。那么怎么解决这个问题呢,下面提供几种方案。

第一种方案,我们在Form1_Load()方法中加一句代码:

     private void Form1_Load(object sender, EventArgs e){Control.CheckForIllegalCrossThreadCalls = false;Thread thread = new Thread(ThreadFuntion);thread.IsBackground = true;thread.Start();}

加入这句代码以后发现程序可以正常运行了。这句代码就是说在这个类中我们不检查跨线程的调用是否合法(如果没有 加这句话运行也没有异常,那么说明系统以及默认的采用了不检查的方式)。然而,这种方法不可取。我们查看 CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异 常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。

下面来看第二种方案,就是使用delegate和invoke来从其他线程中控制控件信息。网上有很多人写了这种控制方式,然而我看了很多这种帖子,表明上看来是没有什么问题的,但是实际上并没有解决这个问题,首先来看网络上的那种不完善的方式:

public partial class Form1 : Form{private delegate void FlushClient();//代理public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){Thread thread = new Thread(CrossThreadFlush);thread.IsBackground=true;thread.Start();}private void CrossThreadFlush(){//将代理绑定到方法FlushClient fc = new FlushClient(ThreadFuntion);this.BeginInvoke(fc);//调用代理}private void ThreadFuntion(){while (true){this.textBox1.Text = DateTime.Now.ToString();Thread.Sleep(1000);}}}

使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了,界面没有响应了。为什么会出现这个问题, 我们只是让新开的线程无限循环刷新,理论上应该不会对主线程产生影响的。其实不然,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得 了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。就算新开的线程中不使用无限循环,使可以返回了。这种方式的使用多线程也失去了它本来 的意义。

现在来让我们看看推荐的解决方案:

public partial class Form1 : Form{private delegate void FlushClient();//代理public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){Thread thread = new Thread(CrossThreadFlush);thread.IsBackground = true;thread.Start();}private void CrossThreadFlush(){while (true){//将sleep和无限循环放在等待异步的外面Thread.Sleep(1000);ThreadFunction();}}private void ThreadFunction(){if (this.textBox1.InvokeRequired)//等待异步{FlushClient fc = new FlushClient(ThreadFunction);this.Invoke(fc);//通过代理调用刷新方法}else{this.textBox1.Text = DateTime.Now.ToString();}}}

运行上述代码,我们可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以再不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。

对于深山老林提出的问题,我最近找到了更优的解决方案,利用了delegate的异步调用,大家可以看看:

public partial class Form1 : Form{private delegate void FlushClient();//代理public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){Thread thread = new Thread(CrossThreadFlush);thread.IsBackground = true;thread.Start();}private void CrossThreadFlush(){FlushClient fc=new FlushClient(ThreadFunction);fc.BeginInvoke(null,null);}private void ThreadFunction(){while (true){this.textBox1.Text = DateTime.Now.ToString();Thread.Sleep(1000);}}}

这种方法也可以直接简化为(因为delegate的异步就是开了一个异步线程):

public partial class Form1 : Form
{private delegate void FlushClient();//代理public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){FlushClient fc=new FlushClient(ThreadFunction);fc.BeginInvoke(null,null);}private void ThreadFunction(){while (true){this.textBox1.Text = DateTime.Now.ToString();Thread.Sleep(1000);}}
}

while (true)和Thread.Sleep(1000);不要放在invoke里面去控制就行了。

[转] c#中 多线程访问winform控件相关推荐

  1. c#,c++,qt中多线程访问UI控件线程的问题汇总

    c#和MFC中可以创建UI控件及模态/非模态对话框,Qt中只能在主UI线程中创建访问UI控件. c#和MFC中可以通过全局变量或指针句柄等方式在工作线程中访问其他UI线程控件,其中c#需要Invoke ...

  2. C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)

    概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现"线程间操作无效: 从不是创建控件的线程访问它"的异常.处理跨线程更新Winform UI控件常用 ...

  3. WinCE5.0移动平台开发笔记(c#中使用多线程访问winform中控件的若干问题(zt))

    本文转载于:http://www.cnblogs.com/zhaotiantang/archive/2009/03/17/1414135.html 我们在做winform应用的时候,大部分情况下都会碰 ...

  4. c#中使用多线程访问winform中控件的若干问题

    我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍. 首先来看传统方法: public partial ...

  5. 在WPF中使用WinForm控件方法

    在WPF中使用WinForm控件方法 原文:在WPF中使用WinForm控件方法 1.      首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,Syste ...

  6. java 线程访问控件_C#多线程与跨线程访问界面控件的方法

    本文实例讲述了C#多线程与跨线程访问界面控件的方法.分享给大家供大家参考.具体分析如下: 在编写WinForm访问WebService时,常会遇到因为网络延迟造成界面卡死的现象.启用新线程去访问Web ...

  7. 异步委托实现多线程winform控件编程

            private void button1_Click(object sender, EventArgs e)         {             ThreadStart ts  ...

  8. MFC中访问界面控件的两种方法

    1.在资源中创建一个对话框资源,放置一些控件,然后使用类向导创建一个此对话框类型的变量,项目中会自动创建此对话框的.h和.cpp文件. 有两种方式可在代码中访问控件. (1)如果在代码中直接访问,则使 ...

  9. WinForm中使用WPF的控件

    在WinForm中可以使用WPF中的控件,或者由WPF创建的自定义控件: 步骤1:创建WinForm工程: 步骤2:在WinForm工程的解决方案资源管理器中,在刚刚创建的WinForm解决方案中新建 ...

最新文章

  1. 学习python时报SyntaxError: Non-ASCII character '\xe5' in file解决方法
  2. javscript对cookie的操作,以及封装
  3. 音视频技术在云会议场景的拓展和未来
  4. [转载]Unix 高手的另外 10 个习惯
  5. 前端工程化:围绕Jenkins打造工作流的过程
  6. opensips简介
  7. 12月29日课程笔记 磁盘格式化与挂载与手动增加swap空间
  8. 深度学习笔记(42) 人脸识别
  9. java redis sadd_Redis Sadd 命令
  10. python图像转矩阵_python 图像转矩阵,矩阵转图像
  11. 零基础学python好学吗-Python0基础好学吗?
  12. IMO船舶材料防火安全规范
  13. 蓝桥杯题目练习 水题 [蓝桥杯2019初赛]矩形切割
  14. python 微信公众号发文章_Python 微信公众号文章爬取
  15. c高级语言程序设计课程设计报告,高级语言程序设计 课程设计报告
  16. R语言中经纬度度分秒转小数
  17. html烟花特效,发射粒子特效,爱心特效,动态祝福、节日祝福网页,时间罗盘,黑客帝国代码雨、文字闪烁、表白爱心网页等等(附下载链接)
  18. 安装显卡后计算机无法启动,Win10更新显卡驱动后无法开机进入系统的解决方法...
  19. FL Studio的音频录制插件Edison
  20. 几何光学学习笔记(30)-6.5光通量和光亮度在光学系统中的传递、像面光照度

热门文章

  1. 常用数据结构及复杂度
  2. 重要接口—Cloneable接口
  3. Python几种加密算法
  4. 华为上机考试题系列(一):牛客网的奇葩操作
  5. 暂时关闭 windows 病毒防护
  6. bzoj 3131 [Sdoi2013]淘金(数位dp)
  7. 获得本机IP和访问服务的端口号(Java)
  8. 【LeetCode-面试算法经典-Java实现】【054-Spiral Matrix(螺旋矩阵)】
  9. Comptia Strata认证考点相关情况【2018.06.05更新】
  10. Tomcat6 ,servlet配置(可用)