在使用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. 【英语】Bingo口语笔记(10) - 常见词汇的缩读

  2. 如何在vmware上创建共享磁盘

    1.先在你本机的vmware安装目录上找到 vmware-vdiskmanager.exe 执行文件. 我的目录是 d:\vmware\vmware-vdiskmanager.exe 再用cmd终端( ...

  3. 有趣的js题目

    ([]).length ({}).length // undefined ([] + {}).length ({} + {}).length 具体解释见此.

  4. 使用Jquery Mobile设计Android通讯录

    本系列教程将指导大家一步步使用Jquery Mobile设计一个Android的通讯录应用.其中在应用的界面部分,将使用jQuery Mobile框架,并且会指导大家如何使Android中提供的web ...

  5. windows 自动关机命令

    Windows 的关机是由Shutdown.exe程序来控制的,位于Windows\System32文件夹中.如果想让Windows 2000也实现同样的效果,可以把Shutdown.exe复制到系统 ...

  6. ios 内存管理 心得

    - alloc, copy, retain会把引用计数+1 - release会把引用计数-1 - 局部变量如果初始化时不是autorelease的,要及时调用release释放,并且赋值为nil否则 ...

  7. swfupload浅谈

    首先,先介绍一个swfUplod吧. SWFUpload是一个客户端文件上传工具,最初由Vinterwebb.se开发,它通过整合flash与javascript技术为web开发者提供了一个具有丰富功 ...

  8. wc命令--Linux统计文件行数

    语法:wc [选项] 文件… 说明:该命令统计给定文件中的字节数.字数.行数.如果没有给出文件名,则从标准输入读取.wc同时也给出所有指定文件的总统计数.字是由空格字符区分开的最大字符串. 该命令各选 ...

  9. PyPI镜像网站

    镜像列表:http://www.pypi-mirrors.org/ 清华镜像:http://e.pypi.python.org/

  10. ren