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();
}
}
}

运行这段代码,我们会看到系统抛出一个异常:

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();
}
}
}

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

//******************************************
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 = ;
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();
ThreadFunction();
}
}
private void ThreadFunction()
{
if (this.listBox1.InvokeRequired)//等待异步
{
FlushClient fc = new FlushClient(ThreadFunction);
this.Invoke(fc); //通过代理调用刷新方法
}
else
{
counter += ;
this.label1.Text = counter.ToString();
this.listBox1.Items.Add(System.DateTime.Now.ToString());
}
}
}
}

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

c#中跨线程调用windows窗体控件的更多相关文章

  1. c#中如何跨线程调用windows窗体控件

    c#中如何跨线程调用windows窗体控件?   我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首 ...

  2. 如何跨线程调用Windows窗体控件

    通过一个子线程来操作主线程中的控件,但是,这样作会出现一个问题(如图1所示),就是TextBox控件是在主线程中创建的,在子线程中并没有对其进行创建,也就是从不是创建控件的线程访问它.那么,如何解决跨 ...

  3. c#中如何跨线程调用windows窗体控件?

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

  4. 如何:对 Windows 窗体控件进行线程安全调用

    http://msdn.microsoft.com/zh-cn/library/ms171728(VS.90).aspx http://msdn.microsoft.com/zh-cn/library ...

  5. 如何在多线程中调用winform窗体控件

    由于 Windows 窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态.还可能出现其他与线程相关的 bug,包 ...

  6. 用于列出选项的Windows窗体控件

    可以提供选项列表的控件有ListBox.ComboBox.CheckedListBox,如何正确的使用和选择这些控件,下面对此进行讨论.首先对这三种控件的功能分别进行说明: ListBox ListB ...

  7. C#多线程应用:子线程更新主窗体控件的值(二)

    在上篇文章中,我已经给大家列了一个在主线程中实现的方式,这篇文章来给大家说说使用Invoke的方式的例子: 对于不代理不太熟悉的朋友,建议先查查相关资料: 例子一: 在C#中,直接在子线程中对窗体上的 ...

  8. Windows窗体控件实现内容拖放(DragDrop)功能

    一.将控件内容拖到其他控件 在开发过程中,经常会有这样的要求,拖动一个控件的数据到另外一个控件中.例如将其中一个ListBox中的数据拖到另一个ListBox中.或者将DataGridView中的数据 ...

  9. vs2017 C# ActiveX浏览器插件 创建 发布 C# windows窗体控件库(.NET Framework)注意事项

    vs2017需要安装插 插件下载地址:https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.Micro ...

随机推荐

  1. 4537: [Hnoi2016]最小公倍数

    Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在有q个询问,每次询问给定四个参数u.v.a和b,请你 ...

  2. VS2013相关资料

    visual studio 主页 http://msdn.microsoft.com/en-us/vstudio/aa718325.aspx vs2013 download http://www.mi ...

  3. [译]36 Days of Web Testing(二)

    Day 7: Http 和 Https Why? 当在网络上传输一些私人,敏感信息时,应该采用加密的手段来保证这些信息在传输的过程中不被侦测到.Https协议正是这种实现机制. Https是一种广泛使 ...

  4. HTML+JS版本的俄罗斯方块

    <!doctype html><html><head></head><body> <div id="box" st ...

  5. 通过CTAPI和Citect SCADA软件进行数据通讯

    官方文档 Citect SCADA 7.20 Technical Reference 参考文献 基于Citect远程控制的变流量堆料控制系统 [王玉增,顾英妮,王维 济南大学,机械工程学院 ,Cite ...

  6. 【NOIP 2011】 观光公交

    题目描述 Description 风景迷人的小城 Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号 ...

  7. 【Tools】Chrome 控制台不完全指南

    Chrome的开发者工具已经强大到没朋友的地步了,特别是其功能丰富界面友好的console,使用得当可以有如下功效: 更高「逼格」更快「开发调试」更强「进阶级的Frontender」 Bug无处遁形「 ...

  8. Palindrome

    poj3974:http://poj.org/problem?id=3974 题意:求给定长度最长回文串的长度. 题解:直接套manacher,搞定. #include<iostream> ...

  9. SQL server 时间日期函数、类型转换

    一.日期与时间函数 二.子查询与分页查询

  10. Android数据存储之文件存储

    首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的. public ...