c#中如何跨线程调用windows窗体控件?
我们在做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);
}
}
}

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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading; namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
private delegate void FlushClient(); //代理
Thread thread = null;
int counter = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.listBox1.Items.Clear();
button1.Enabled = false;
thread = new Thread(CrossThreadFlush);
thread.IsBackground = true;
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread.Suspend();
button1.Enabled = true;
}
private void CrossThreadFlush()
{
while (true)
{
//将sleep和无限循环放在等待异步的外面
Thread.Sleep(1000);
ThreadFunction();
}
}
private void ThreadFunction()
{
if (this.listBox1.InvokeRequired)//等待异步
{
FlushClient fc = new FlushClient(ThreadFunction);
this.Invoke(fc); //通过代理调用刷新方法
}
else
{
counter += 1;
this.label1.Text = counter.ToString();
this.listBox1.Items.Add(System.DateTime.Now.ToString());
}
}
}
}

运行上述代码,我们可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以在不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。
原文:http://www.cnblogs.com/zhaotiantang/archive/2009/03/17/1414135.html
c#中如何跨线程调用windows窗体控件?的更多相关文章
- c#中如何跨线程调用windows窗体控件
c#中如何跨线程调用windows窗体控件? 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首 ...
- 如何跨线程调用Windows窗体控件
通过一个子线程来操作主线程中的控件,但是,这样作会出现一个问题(如图1所示),就是TextBox控件是在主线程中创建的,在子线程中并没有对其进行创建,也就是从不是创建控件的线程访问它.那么,如何解决跨 ...
- c#中跨线程调用windows窗体控件
c#中跨线程调用windows窗体控件解决. 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首先来 ...
- 如何:对 Windows 窗体控件进行线程安全调用
http://msdn.microsoft.com/zh-cn/library/ms171728(VS.90).aspx http://msdn.microsoft.com/zh-cn/library ...
- 如何在多线程中调用winform窗体控件
由于 Windows 窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态.还可能出现其他与线程相关的 bug,包 ...
- [WinForm]WinForm跨线程UI操作常用控件类大全
前言 在C#开发的WinForm窗体程序开发的时候,经常会使用多线程处理一些比较耗时之类的操作.不过会有一个问题:就是涉及到跨线程操作UI元素. 相信才开始接触的人一定会遇上这个问题. 为了解决这个问 ...
- 实现Winform 跨线程安全访问UI控件
在多线程操作WinForm窗体上的控件时,出现“线程间操作无效:从不是创建控件XXXX的线程访问它”,那是因为默认情况下,在Windows应用程序中,.NET Framework不允许在一个线程中直接 ...
- 用于列出选项的Windows窗体控件
可以提供选项列表的控件有ListBox.ComboBox.CheckedListBox,如何正确的使用和选择这些控件,下面对此进行讨论.首先对这三种控件的功能分别进行说明: ListBox ListB ...
- WPF跨线程操作UI界面控件
在WPF应用中,如果遇到多线程的需求时,如果引用WPF控件时会引发异常,异常内容:调用线程无法访问此对象,因为另一个线程拥有该对象.具体如下: 调用代码: ThreadcountThread= ...
随机推荐
- React.js再探(二)
上文中说到了组件了. 我们使用组件的目的最大莫过于复用,提供生产效率. 那么,这时候组件就应该能够提供一些”api”出来,让开发者去定义在不同场景下的不同表现,比如,行为或外观等. 而这些“api”就 ...
- EF中的EntityState几个状态的说明
之前使用EF,我们都是通过调用SaveChanges方法把增加/修改/删除的数据提交到数据库,但是上下文是如何知道实体对象是增加.修改还是删除呢?答案是通过EntityState枚举来判断的,我们看一 ...
- JS常用方法总结,及jquery异步调用后台方法实例
//前台接收get参数值 function getQueryString(name) { var queryStrings = window.location.search.sp ...
- 【Linux】Vim编辑器-批量注释与反注释
[-] vim编辑器---批量注释与反注释 方法一 块选择模式 插入注释 取消注释 方法二 替换命令 批量注释 取消注释 实例演示 vim编辑器---批量注释与反注释 在使用vim编写代码的时候, ...
- HDU 1686 Oulipo(kmp)
Problem Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, w ...
- 计算4000000000内的最大f(n)=n值---字符串的问题python实现(五岁以下儿童)
问题: 写一个函数,计算4 000 000 000 以内的最大的那个f(n)=n的值,函数f的功能是统计全部0到n之间全部含有数字1的数字和.比方:f(13)= 6,由于"1"在& ...
- Java设计模式之装饰者模式
要实现装饰者模式,注意一下几点内容: 1.装饰者类要实现真实类同样的接口 2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入) 3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相 ...
- javascript系列之核心知识点(二)
变量对象 变量对象是一个与执行上下文相关联的容器.它是一个和上下文密切结合的特殊对象,含有定义在上下文中的变量和函数声明.注意,函数表达式(和函数声明不同的)不包含在变量对象中. 变量对象 ...
- UVa 740 - Baudot Data Communication Code
称号:目前编码,他们shift键被按下,并提出,对应的两个编码,其中,2相应的编码shift操作. 给你适当的编码值.寻求相应的字符串. 分析:模拟.字符串. 简单题,标记shift的升降分类处理就可 ...
- 文件同步服务器,iis 集群 ,代码同步(一)
文件同步服务器 BitTorrent Sync 有点像TeamViewer远程协助 软件,私钥连接. 使用版本就30 天,最近测试了,功能不够理想.有点遗憾,我觉得我可以写一个! 确实很好用.