在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常。这是微软为了保证线程安全以及提高代码的效率所做的改进,但是也给大家带来很多不便。

其实解决这个问题有两种方法:
一,是通过设置
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
在你的程序初始化的时候设置了这个属性,而且在你的控件中使用的都是微软Framework类库中的控件的话,系统就不会再抛出你上面所说的这个错误了。
二,就是委托了,个人建议用这种方法
首先在WinForm窗体中拖入ListBox控件,然后参照以下代码:
Thread t1;//声明一个全局线程 private void Form1_Load(object sender, EventArgs e) { t1 = new Thread(new ThreadStart(BackgroundProcess)); t1.Start(); //开始 } delegate void aa(); private void BackgroundProcess() { // 将委托实例化 aa a= delegate() { for (int i = 0; i < 50; i++) { listBox1.Items.Add("Iterations: " + i.ToString()); Thread.Sleep(300); listBox1.Refresh(); } }; listBox1.Invoke(a); }

来源:http://www.huomo.cn/developer/article-1aa8.html

C#多线程操作界面控件的解决方案

我们在做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=new FlushClient(ThreadFunction);­ FlushClient.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)­ {­ Thread thread = new Thread(CrossThreadFlush);­ FlushClient=new FlushClient(ThreadFunction); ­ FlushClient.BeginInvoke(null,null);­ }­ private void ThreadFunction()­ {­ while (true)­ {­ this.textBox1.Text = DateTime.Now.ToString();­ Thread.Sleep(1000);­ }­ ­ }­ }

C#中利用委托实现多线程跨线程操作的更多相关文章

  1. WinForm中新开一个线程操作 窗体上的控件(跨线程操作控件)

    最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录窗体的显示,开了一个线程去加载数据远程的数据,会报一个错误"线程间操作无效: 从不是 ...

  2. C#跨线程操作控件的最简单实现探究

    随着程序复杂度的提高,程序不可避免会出现多个线程,此时就很可能存在跨线程操作控件的问题. 跨线程操作UI控件主要有三类方式: 1.禁止系统的线程间操作检查.(此法不建议使用) 2.使用Invoke(同 ...

  3. C# 跨线程操作控件(简洁)

                                              C# 跨线程操作控件 .net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生.解决此问题的方法有两个: 第一 ...

  4. 扩展BindingList,防止增加、删除项时自动更新界面而不出现“跨线程操作界面控件 corss thread operation”异常

    在做界面程序时,常常需要一些数据类,界面元素通过绑定等方式显示出数据,然而由于UI线程不是线程安全的,一般都需要通过Invoke等方式来调用界面控件.但对于数据绑定bindingList而言,没法响应 ...

  5. Winform跨线程操作界面的策略

    BeginInvoke(new ThreadStart(() => toolStripButton1.Text = "aaa")); 1.非跨线程操作和部分跨线程get不会引 ...

  6. 处理跨线程操作问题(使用Action和delegate或lambda表达式)

    方法A: Action f = () =>                    {                       txtProcess.Text = "开始更新程序.. ...

  7. jQuery中利用JSONP解决AJAX跨域问题

    写在前面 跨域的解决方案有多种,其中最常见的是使用同一服务器下的代理来获取远端数据,再通过ajax进行读取,而在这期间经过了两次请求过程,使得获取数据的效率大大降低,这篇文章蓝飞就为大家介绍一下解决跨 ...

  8. WPF中窗口控件的跨线程调用

    在WinForm中,我们要跨线程访问窗口控件,只需要设置属性CheckForIllegalCrossThreadCalls = false;即可. 在WPF中要麻烦一下,同样的不允许跨线程访问,因为没 ...

  9. Unity中利用委托与监听解耦合的思路

    这篇随笔是一篇记录性的随笔,记录了从http://www.sikiedu.com/my/course/304,这门课程中学到的内容,附带了一些自己的思考. 一.单例模式的应用 首先假想一种情况,现在需 ...

随机推荐

  1. 通过外部接口 根据ip获取城市名

    3种接口 淘宝/百度/不知名/   推荐淘宝接口 ip自个去获取,下附带php 获取ip的示例 function getIP() { static $realip; if (isset($_SERVE ...

  2. AsyncTask类

    1.定义         异步任务类,在类中实现异步操作,并提供回调方法反馈当前异步执行的程度,最后反馈 的结果提供给UI主线程.         <1>Android线程         ...

  3. AndroidManifest修改重打包全过程

    AndroidManifest修改重打包全过程: 作者: 蔡建良 2013-06-26 准备工具:apktool.jar和signapk.jar 下载: http://download.csdn.ne ...

  4. php.ini中Magic_Quotes_Gpc开关设置

    如果你网站空间的php.ini文件里的magic_quotes_gpc设成了off,那么PHP就不会在敏感字符前加上反斜杠(\\),由于表单提交的内容可能含有敏感字符,如单引号('),就导致了SQL ...

  5. linux umask使用详解

    转自:http://blog.csdn.net/lmh12506/article/details/7281910 umask使用方法 A 什么是umask?   当我们登录系统之后创建一个文件总是有一 ...

  6. Fisher information matrix笔记

    在看FK论文时,fisher information matrix是必须理解的. 从维基百科查阅到,Fisher information matrix是用利用最大似然函数估计来计算方差矩阵. 来源于: ...

  7. 重新安装python

    1. 在上次进行安装python的时候,很多东西不能用,例如后退键,删除键,都是不能在命令行中使用,主要原因是在编译python的时候,相关的安装包没有进行安装,从而导致出现乱码,在编译最新版本的py ...

  8. 【LeetCode】7 & 8 - Reverse Integer & String to Integer (atoi)

    7 - Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 Notic ...

  9. 跨站脚本攻击(Cross‐Site Scripting (XSS))实践

    作者发现博客园在首页显示摘要时未做html标签的过滤,致使摘要中的html代码可以被执行,从而可以注入任何想要被执行的js代码,作者利用这一缺陷在本文摘要中插入了一段js代码执行alert弹窗,同时增 ...

  10. Ubuntu 下一个可用的音乐播放器

    参考:http://www.pairsdoll.com/install-audacious-music-palyer-in-ubuntu.html/ 方法:打开terminal,sudo apt-ge ...