跨线程访问控件

【转帖】 

我们在做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等等,虽然可以解决问题,但其高昂的价格却往往令人…

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

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

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

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

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…

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/…

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

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

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

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

OpenGL.Tutorial15_Lightmaps

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

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

 提示:点击上方"NX网"↑ 免费订阅 关注老叶NC程序演示:%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…

catia v5法矢数据软件_catia介绍

CATIA是英文 Computer Aided Tri-Dimensional Interface Application 的缩写。 是世界上一种主流的CAD/CAE/CAM 一体化软件。在70年代Dassault Aviation 成为了第一个用户,CATIA 也应运而生。从1982年到1988年,CATIA 相继发布了1版本、2版本、3版本&…

(十七)WebGIS中距离及面积测量的原理和实现以及坐标转换的简单介绍

文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/。 1.背景 在这一章里我们将讨论基础工具栏中另外两个常用工具:距离测量工具盒面积测量工具。 距离测量工具要求实现如下功能: a.通…

access查询出生日期格式转换_从身份证中提取出生日期的3个方法和计算年龄和星座的方法...

在我们日常的工作当中,经常会遇到通过身份证来获取出生年月日的需求,今天就给大家介绍三种可以从身份证中提取出生年月日的方法。我们都知道身份证不同的区域是有不同的含义的,代表出生年月日的数字是第7位到第14位,也就说我们把这…

AutoRun Pro Enterprise II 教程--- 教你制作软件工具箱教程清晰版(教程画面清晰,教程语音可以调高)...

AutoRun Pro Enterprise II是一款功能极为强大的自动运行菜单制作工具。可在一个所见即所得的环境中创建并编辑一个专业的CD、DVD自动运行界面并生成自动运行文件。在自动运行界面中支持打开或执行文件,打印文档,发送邮件,访问站点&#xff0…

access如何设置定期报表汇总_报表工具选型对比系列 - 大报表

有些报表查询出的数据行数可达千万甚至上亿,这类报表通常被叫做大报表,大多数情况下都是些清单明细数据报表,也有少量分组报表。针对大报表,如果像常规报表一样,将数据一次性全取再交给前端呈现是不可行的。一是等待时…

PLSQL Developer远程连接oracle数据库

前提是本机已经安装oracle,利用 net configuration assistant 。若本机没有安装oracle,无需装oracle的方法请点我打开net configuration assistant,选择“本地网络服务名配置,如下图所示然后选择添加服务名选择远程数据库实例名主…

spad 探测器_大面阵SPAD阵列集成微透镜阵列,填充因子改善明显

基于CMOS制造工艺可实现大面阵、单片式单光子雪崩光电二极管(SPAD)阵列,并受到如3D成像、荧光寿命成像等各种应用的青睐,但常常受到低填充因子(fill factor,指感光区域面积与像元面积的比值)的困扰。SPAD填充因子的数值通常小于5%&#xff0c…

Azure Backup 简介

ViswanathTata云Enterprise 项目经理AzureBackup是 Azure恢复服务的一部分,在安全高效的环境中对上传到 Azure的数据提供简单可靠的管理和保护。Azure Backup以经济高效的方式提供无限的存储空间和长期的数据保留,这些功能使其成…

笔记:Java虚拟机运行时数据区

Java虚拟机在执行Java程序的过程中会把它管的内存划分为以下若干个不同的区域: 1、程序计数器 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器;由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时…

高电压技术思维导图_钢铁技术:钢铁行业板坯连铸结晶器振动常见故障思维导图...

钢铁虾:(您距离钢铁虾只差关注)结晶器是连铸机的心脏,其振动偏差直接危及连铸过程的生产安全,其振动精度也往往与铸坯表面裂纹等缺陷息息相关。国内外常见板坯连铸结晶器振动形式有:①机械式振动;②双液压缸式振动&…