跨线程访问控件

【转帖】 

我们在做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多线程控件的控制了。

 

通过主线程的委托 去调用控件就不算是跨线程访问控件了。


ContractedBlock.gifExpandedBlockStart.gifCode
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication1
{
    
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.label1.InvokeRequired)//等待异步
            {
                FlushClient fc 
= new FlushClient(ThreadFunction);
                
this.label1.Invoke(fc);//通过代理调用刷新方法
            }
            
else//这里在什么情况下执行呢,在this.label1.Invoke(fc)时执行,以为fc是主线程的委托FlushClient的实例,所以InvokeRequired为false
            {
                
this.label1.Text = DateTime.Now.ToString();
                
            }
        }
    }
}

前台线程和后台线程:一旦所有前台线程在托管进程(其中 .exe 文件是托管程序集)中被停止,系统将停止所有后台线程并关闭,主线程就是后台线程。所有的后台线程在应用程序退出时都会自动结束。应用程序必须运行完所有的前台线程才可以退出。

转载于:https://www.cnblogs.com/shineqiujuan/archive/2009/11/12/1601503.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/264142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解析Nginx负载均衡

摘要:对于一个大型网站来说,负载均衡是永恒的话题。随着硬件技术的迅猛发展,越来越多的负载均衡硬件设备涌现出来,如F5 BIG-IP、Citrix NetScaler、Radware等等,虽然可以解决问题,但其高昂的价格却往往令人…

基于vue+mint-ui的mobile-h5的项目说明

基于vuemint-ui的mobile-h5的项目说明转载于:https://www.cnblogs.com/ysx215/p/10768656.html

Ubuntu20.04更换为国内源

Ubuntu20.04更换为国内源 1、打开Linux终端,执行下列命令,将源文件备份,以防万一。 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak2、选择下列任意一个源,将其复制 ​ 2.1 阿里源 deb http://mirrors.aliyun.com/…

深圳办理cdn经营许可证_深圳危化品经营许可证申请流程怎么申请?办理危化学品经营许可证...

随着深圳地区慢慢的进入了产业整合和城市规划规范化的运营中,很多涉及到生产的公司都逐渐被有效的整合在一起了,而随着深圳地区越发有效的整合生产规划,很多地区都逐渐的在将涉及到危险化学品生产和经营的企业都进行合理的管制,在…

Discuz!NT 缓存设计简析 [原创]

作为一个社区类型软件,大并发支持和高效稳定运行永远是“硬道理”,而有效安全的使用缓存恰恰能起到事倍功半的效果。而.NET本身所提供的缓存机制又显得过于“单薄”,比如说订制不太灵活方便, 缓存对象之间层次感不强, 使用时缺乏统一的管理等…

实验七:Xen环境下cirrOS的安装配置

实验名称: Xen环境下cirrOS的安装配置 实验环境: 这里的cirrOS和实验六中的busybox的启动方式相同,唯一的区别就是我们使用的cirrOS镜像中,已经包含了根文件系统、内核文件以及ramdisk和grub程序; 只需要我们使用xen环…

携程SQL面试题忘大牛解答解决思路

讨论地址:http://bbs.csdn.net/topics/380208742

VSCode从下载到配置Ubuntu系统

Visual Studio Code从下载到配置Ubuntu系统 一、下载和安装Visual Studio Code 1、进入Visual Studio Code官网(Visual Studio Code - Code Editing. Redefined),点击箭头所指地方下载红框内的安装包; 2、因为是国外网址下载&am…

python 写入excel 日期_Python实例:excel文档写入操作

来自PythonABC.org老师的课程很好,但是每个视频都蛮长的,听着听着就有些晕乎,所以根据视频自己整理了一下,以便记录学习使用Python实现excel的文档写操作import openpyxl from openpyxl.utils import get_column_letterwb openpy…

Windows软件调试学习笔记(1)

——WINDBG中的表达式 WINDBG接受两种表达式,C表达式和MASM表达式。 1、 MASM表达式中的数值: MASM表达式中的数值可以基于16,10,8,2四种进制。用n命令可以设置WINDBG的缺省进制,如果没有设置过则默认为16。…

eclipse集成maven插件

一、准备工作 1. 安装jdk并配置:https://www.cnblogs.com/diandiangui/p/10002100.html  2. 已安装好 maven并配置:https://www.cnblogs.com/diandiangui/p/10768339.html  3. 安装eclipse并配置:https://www.cnblogs.com/diandiangui/p/…

VMware ESX与VMware ESXi区别

VMware ESX与VMware ESXi区别 2011-04-05 10:24:06| 分类: 虚拟机 | 标签: |字号大中小 订阅 VMware ESX 与 VMware ESXi 区别 前几天去一家公司看到一本书介绍VMWare ESXi ,就随手翻了翻,之前我在公司也架设过VMWare ESXi 4.0…

批量改名_手把手教你用Python批量给图片添加水印 | 知了干货分享

我们在网上浏览一些文章的时候,经常会发现文章中会有一些图片,上面会有一些标识,而这些标识就是我们经常说的水印了。很多时候,我们需要给图片加上一些修饰,好让别人能直观的认识到这个图片的出处以及来源,…

linux环境下安装nginx步骤(不错)

开始前,请确认gcc g开发类库是否装好,默认已经安装。 ububtu平台编译环境可以使用以下指令 apt-get install build-essential apt-get install libtool centos平台编译环境使用如下指令 安装make: yum -y install gcc automake autoconf libt…

090609 T 领域建模

领域建模的重要性 以数据为中心的应用程序开发,面向过程分析方法的核心在于对数据库的设计。 而现在以面向对象的方式进行分析(OOA,OOD)时,领域建模就替换了上述方法的地位。在建模的同时,对需求有一…

配置apache、php、mysql之间的关系

1、index.php文件放入/usr/local/apache2/htdocs 目录下 其中index.php里面内容为&#xff1a; <?phpphpinfo();$dbc mysql_connect("127.0.0.1","root","win2009");if(!$dbc) {echo"数据库链接(面向过程)错误!";}else{echo"…

OpenGL.Tutorial15_Lightmaps

ZC&#xff1a;撤销 & 重做 — Blender Manual.html&#xff08;https://docs.blender.org/manual/zh-hans/dev/interface/undo_redo.html&#xff09; ZC&#xff1a;Blender下载地址&#xff1a;Index of _release_Blender2.50alpha_.html&#xff08;https://download.b…

后处理没有pui文件怎么打开_UG NX10.0四轴后处理下载(带PUI文件)

&#xfeff; 提示&#xff1a;点击上方"NX网"↑ 免费订阅 关注老叶NC程序演示&#xff1a;%G40 G17 G94 G80 G90M05M09G91 G28 Z0.0M01T00 M06(Tool NaneD4R0.5 XY 0.10mm Z0.00mm)(D4.00 R0.50 FL50.00 L75.00)G00 G90 G55 X68.263 Y.969 A187.77 S4500 M03G43 Z79…

java调用oracle 存储过程 以及游标使用

打开 PLSQL 创建一张&#xff1a;如果你没有PLSQL 找我 -- Create tablecreate table T_QUN_STUDY( T_ID NUMBER not null, T_NAME VARCHAR2(50), T_PASSWORD VARCHAR2(50))tablespace USERS pctfree 10 initrans 1 maxtrans 255 storage ( initial 64 …

日志处理中一些shell命令技巧

日志处理中一些shell命令技巧 阴差阳错的做的日志分析&#xff0c;前途未卜的这段日子&#xff0c;唯一还有点意思的可能就是手动的处理大量日志。总结一下。 日志文件的输入是动则几个G的文本。从N个这样的文件中得到一个列表&#xff0c;一个数字&#xff0c;一个比例。在什么…