本文转载于:http://www.cnblogs.com/zhaotiantang/archive/2009/03/17/1414135.html

我们在做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)
        {
             FlushClient=new FlushClient(ThreadFunction);

FlushClient.BeginInvoke(null,null);
        }

private void ThreadFunction()
        {

while (true)
            {
                this.textBox1.Text = DateTime.Now.ToString();
                Thread.Sleep(1000);
            }

}
    }

转载于:https://www.cnblogs.com/EverShine/archive/2011/07/07/2100252.html

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

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

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

  2. [转] c#中 多线程访问winform控件

    原文 c#中多线程访问winform控件的若干问题小结 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来解决这个问题,下面我将详细的 ...

  3. C#中使用多线程访问Winform问题解决方案

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

  4. Cesium 开发笔记-Vue 中使用 Cesium(vue-cli-plugin-cesium)

    Cesium 开发笔记-Vue 中使用 Cesium(vue-cli-plugin-cesium) 通常情况下,我们要在 Vue 中使用 Cesium,首先要安装 Cesium,然后要在 vue-cl ...

  5. 【QT开发笔记-基础篇】| 第二章 常用控件 | 2.12 表格控件 QTableWidget

    本节对应的视频讲解:B_站_链_接 QTableWidget 是 Qt 中的表格控件,可以行列的形式来展示数据 1. 属性和方法 QTableWidget 有很多属性和方法,完整的可查看帮助文档. 在 ...

  6. C#在一个form中改变另一个form中控件的内容、C#做登录界面并且密码显示为*

    C#中在一个窗体中改变另外一个窗体中控件的显示 这个问题可以用来改变messageBox中默认显示的"确定",可以使用此方法重新写一个窗体,显示OK: 方法: 1.将要改变的for ...

  7. 微信公众平台开发笔记

    从寒假自己就开始拿微信公众平台开发当练手,到现在断断续续已经挺久了,只不过忙于其他事写代码的时间还是很少,但整体的框架已经搭起来了.公众微信号就不用给了,我不求粉,只是来总结一下技术问题,再拖很多东西 ...

  8. Android开发笔记(三十七)按钮类控件

    Button与ImageButton Button是文本按钮(继承自TextView),而ImageButton是图像按钮(继承自ImageView).两者之间的区别在于: 1.Button即可显示文 ...

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

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

最新文章

  1. Rabbitmq消息发送事务与确认机制
  2. python localtime 与utc时间差5分钟_在linux中用localtime()显示的时间与实际时间不相符,不是与北京时间差8个小时,而是差15个小时...
  3. [笔记]提升R的性能和突破内存限制的技巧
  4. 46 FI配置-财务会计-固定资产-一般评估-指定平行货币的使用
  5. android常用网址
  6. IDEA的常用配置一键导入及优化内存
  7. C#指南,重温基础,展望远方!(5)C#语句
  8. 网上商城后台架构设计
  9. NetCore控制台实现自定义CommandLine功能
  10. [译]C语言实现一个简易的Hash table(2)
  11. Web 网页开发的一点心得
  12. VTK(五)---内窥镜漫游(基于VMTK血管中心线提取)
  13. mysql两个下拉框_两个下拉框的纠葛
  14. Github的安装和使用
  15. LEAM(生活/生命体验算法模型)
  16. 网络基础 — IP地址和子网掩码
  17. app消息推送(ios/android)基础知识
  18. 无线系列 - 5G大规模MIMO阵列仿真及混合波束成形设计
  19. 遗传算法_粒子群算法优化支持向量机分类预测-附代码
  20. 拿高分文章,还得是Synaptic Systems 微管蛋白抗体

热门文章

  1. Spring Boot第四篇:SpringBoot 整合JPA
  2. Python数据处理入门教程!
  3. 常见的神经网络求导总结!
  4. 集成模型Xgboost!机器学习最热研究方向入门,附学习路线图
  5. PYTHON编程导论群问题汇总(一)
  6. 任天堂经典游戏可以体感操作了,打开网页就能玩,击败泰森不是梦
  7. 吴恩达老师,被曝靠「教书」实现首个IPO上市,估值50亿美元
  8. 用意念就能控制的操作系统?这家华人团队做的脑机接口,3个电极实现脑波成像...
  9. 用 Pytorch 理解卷积网络
  10. 双十一来这儿,华为昇腾的秘密都给你!