本来是写完线程池就结束多线程总结之旅系列的,但是想想平时在项目中用到线程仅仅不够的,为什么这么说呢?举个例子:我们有一个函数,它的功能就是加载数据,然后绑定到datagridview。现在我们开启一个线程去执行这个函数。结果可想而知,它会报错:提示线程无法访问。。。之类的话。为什么报错呢?因为你在开启的线程中操作了datagridview控件,也就是你跨线程调用控件了。

  那么我们应该怎么跨线程调用控件呢?下面我就把我总结的几种方法奉献给各位。

  跨线程调用控件的几种方法:

  1、方法一:Control.CheckForIllegalCrossThreadCalls = false;这是通过禁止编译器检查对跨线程访问操作,但是这种方法不是安全的解决办法,尽量不要使用。

  为什么说不安全呢?

    (1)我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。

    (2)一般对于跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了。

    代码下载:http://files.cnblogs.com/files/qtiger/CheckForIllegalCrossThreadCalls.rar

  2、方法二: 使用Delegate和Invoke跨线程调用控件(也叫代理方式)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApplication1
{public partial class Form1 : Form{public Form1(){InitializeComponent();           }private void button1_Click(object sender, EventArgs e){Thread t = new Thread(ModifyLabelText);t.Start();}/// <summary>/// 定义委托/// </summary>private delegate void InvokeDelegate();/// <summary>/// this.label1.InvokeRequired就是问问我们要不要使用代理执行ModifyLabelText方法/// </summary>private void ModifyLabelText(){//使用Invoke代理的方式调用ModifyLabelText方法if (this.label1.InvokeRequired){InvokeDelegate invokeDelegate=new InvokeDelegate(ModifyLabelText);this.Invoke(invokeDelegate);                }else{this.label1.Text = "我已经跨线程修改了Label的值";}}}
}

  代码下载:http://files.cnblogs.com/files/qtiger/InvokeAndDelegate.zip

  3、方法三:使用BeginInvoke和Delegate的方式。(也叫代理方式)

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApplication1
{public partial class Form1 : Form{public Form1(){InitializeComponent();           }private void button1_Click(object sender, EventArgs e){Thread t = new Thread(ModifyLabelText);t.Start();}/// <summary>/// 定义委托/// </summary>private delegate void InvokeDelegate();/// <summary>/// this.label1.InvokeRequired就是问问我们要不要使用代理执行ModifyLabelText方法/// </summary>private void ModifyLabelText(){//使用BeginInvoke代理的方式调用ModifyLabelText方法if (this.label1.InvokeRequired){InvokeDelegate invokeDelegate=new InvokeDelegate(ModifyLabelText);this.BeginInvoke(invokeDelegate);                }else{this.label1.Text = "我已经跨线程修改了Label的值";}}}
}

  在这里进行一下说明:Invoke方法和BeginInvoke方法的区别是Invoke方法是同步的, 它会等待工作线程完成;BeginInvoke方法是异步的, 它会另起一个线程去完成工作线程。

  代码下载:http://files.cnblogs.com/files/qtiger/BeginInvokeAndDelegate.zip

  4、方法四:使用BackgroundWorker组件(推荐使用这个方法)

   (1)概述:BackgroundWorker是·net里用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 始终处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用BackgroundWorker类方便地解决问题。

  (2)工作原理:该控件有三个事件:DoWork 、ProgressChanged 和 RunWorkerCompleted。在程序中调用RunWorkerAsync方法则会启动DoWork事件的事件处理,当在事件处理过程中,调用 ReportProgress方法则会启动ProgressChanged事件的事件处理,而当DoWork事件处理完成时,则会触发RunWorkerCompleted事件。

您必须非常小心,确保在 DoWork 事件处理程序中不操作任何用户界面对象(否则仍会停止响应)。而应该通过 ProgressChanged和 RunWorkerCompleted 事件与用户界面进行通信。

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WorkerBackgrounderExmple
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private static int MaxRecords = 100;private void btnStart_Click(object sender, EventArgs e){if (backgroundWorker1.IsBusy){return;}this.listView1.Items.Clear();this.backgroundWorker1.RunWorkerAsync(MaxRecords);this.btnStart.Enabled= false;this.btnCancel.Enabled= true;}private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){try{e.Result = this.RetrieveData(this.backgroundWorker1, e);}catch (Exception ex){MessageBox.Show(ex.Message);throw;}}private int RetrieveData(BackgroundWorker worker, DoWorkEventArgs e){int maxRecords=(int)e.Argument;int percent=0;for (int i = 1; i <=maxRecords; i++){if (worker.CancellationPending){return i;}percent=(int)(((double)i/(double)maxRecords)*100);worker.ReportProgress(percent, new KeyValuePair<int, string>(i, Guid.NewGuid().ToString()));Thread.Sleep(100);}return maxRecords;}private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e){KeyValuePair<int, string> record = (KeyValuePair<int, string>)e.UserState;this.label1.Text = string.Format("There are {0} records retrieved!", record.Key);this.progressBar1.Value = e.ProgressPercentage;this.listView1.Items.Add(record.Value);}private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){try{this.label1.Text = string.Format("Total records: {0}", e.Result);this.btnStart.Enabled = true;this.btnCancel.Enabled = false;}catch (TargetInvocationException ex){MessageBox.Show(ex.InnerException.GetType().ToString());}}private void btnCancel_Click(object sender, EventArgs e){this.backgroundWorker1.CancelAsync();}}
}

  源码下载:http://files.cnblogs.com/files/qtiger/WorkerBackgrounderExmple.zip

  多线程这一块就总结到这了,都是平时自己总结的东西,希望对大家有用,有机会把事件和委托总结一下。

转载于:https://www.cnblogs.com/qtiger/p/5834320.html

多线程总结之旅(12):跨线程调用控件的几种方式相关推荐

  1. C# 跨线程调用控件

    在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁 ...

  2. 跨线程调用控件之MethodInvoker

    这是一部分重要的代码,用VS2005通过. 使用到两个控件,一个按钮button1,一个标签label1. private void button1_Click(object sender, Even ...

  3. c#跨线程操作控件(有UI操作)|及多线程操作

    仅记录(好多大佬都会): 跨线程操作UI控件 ※在.NET2.0之后为了线程之间的安全,不允许跨线程操作控件,最简单的解决办法是禁止检查,但一般不猜用此方法,会造成各线程之间的混乱,可用作临时调试使用 ...

  4. C#跨线程操作控件的线程安全方法

    C#跨线程操作控件的线程安全方法 在C#中,经常用到这样一个场景,Windows Form程序启动一个工作者线程执行一部分工作,这样做是为了避免速度慢的工作如果直接调用会使得主Form停止响应一段时间 ...

  5. c# winform InvokeRequired 解决跨线程访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它. Windows 窗体中 ...

  6. 跨线程取出控件的值的写法(不是跨线程赋予控件值)

    //这个方法是跨线程取出控件的值,不是跨线程赋予控件值private delegate void DelegateGetControl(各种参数);private void GetControl(各种 ...

  7. WinForm中新开一个线程操作窗体上的控件(跨线程操作控件)GOOD

    http://www.cnblogs.com/joey0210/p/3450379.html 最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录 ...

  8. c#使用MethodInvoker解决跨线程访问控件

    c#使用MethodInvoker解决跨线程访问控件 .net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生,有一种方法是禁止编译器对跨线程访问作检查,Control.CheckForIlle ...

  9. 在.Net中进行跨线程的控件操作(上篇:Control.Invoke)

    本文的重点在于介绍如何在多线程编程中,从非UI线程上访问界面中的控件.有过多线程编程经验的人都知道,当我们在非UI线程上试图给一个界面中的控件赋值的时候,比如说label的Text属性,系统会抛出一个 ...

最新文章

  1. 让程序主窗口不显示在任务栏中
  2. python3.7安装numpy pandas失败的处理方案
  3. java 线程的几种状态
  4. 大话设计模式—备忘录模式
  5. api签名_使用签名保护基于HTTP的API
  6. 伪命题:我们来谈谈校招生起薪的问题,它对你来说重要吗?
  7. linux 脚本调用企业微信_shell或python调用企业微信发送消息(实现报警功能)
  8. 为什么vi用HJKL和ESC
  9. linux input设备冲突,linux input设备怎么固定event handler
  10. Linux开发环境的搭建和使用——Linux本必备软件SSH
  11. 请问投稿中要求上传的author_SCI投稿状态解析
  12. 嵌入式学习--1线协议(以ds18b20为例)
  13. 换脸算法 X2Face 详解
  14. win10调整鼠标滚轮方向
  15. MVC.MVVM.MVP的理解
  16. UTC时间转成北京时间
  17. leetcode-初级算法-数组-有效的数独(JavaScript)
  18. HTML/JSP中一些单书名号标签的用途
  19. CF1658F 题解
  20. orb-slam系列 LocalMapping线程 开始(八)

热门文章

  1. JavaScript高级笔记
  2. 模块开发卷宗(GB8567——88)
  3. 大数据平台应用 17 个知识点汇总
  4. 大数据最核心的关键技术——32个算法,记得收藏!
  5. JVM插桩之四:Java动态代理机制的对比(JDK和CGLIB,Javassist,ASM)
  6. TensorFlow搭建简易Wide and Deep 模型
  7. HBase总结(二十)HBase常用shell命令详细说明
  8. Ubuntu 16.04安装Cobbler 2.9
  9. 系统目录结构,文件类型
  10. Linux RHCS中心跳网络接口的指定