多线程总结之旅(112):跨线程调用控件的几种方式

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

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

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

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

  为什么说不安全呢?

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

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

    代码下载:

  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的值";
            }

        }
    }
}

  

  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的值";
            }

        }
    }
}

  在这里进行一下说明:

  

时间: 2024-12-20 09:10:54

多线程总结之旅(112):跨线程调用控件的几种方式的相关文章

C# 跨线程调用控件

在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁止编译器对跨线程访问做检查 第二种办法: 使用delegate和invoke来从其他线程中调用控件 第三种办法: 使用delegate和BeginInvoke来从其他线程中控制控件 第四种办法: 使用BackgroundWorker组件 源代码下载 线程间操作无效 界面上有一个button和一个la

【转载】C# 跨线程调用控件

转自:http://www.cnblogs.com/TankXiao/p/3348292.html 感谢原作者,转载以备后用 在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁止编译器对跨线程访问做检查 第二种办法: 使用delegate和invoke来从其他线程中调用控件 第三种办法: 使用delegate和BeginInvoke来从其他线程中控

.net跨线程调用控件

其实这不是新知识,今天刚好遇到了,就发一贴吧. 有两种方法. 方法一:掩耳盗铃(不推荐) 1 public Form1() 2 { 3 InitializeComponent(); 4 Control.CheckForIllegalCrossThreadCalls = true;//不捕获错误线程的调用 5 } 方法二:调用控件的Invoke方法(推荐) 1 Thread thread = new Thread(() => 2 { 3 textBox1.Invoke(new Action<st

WinForm与WPF下跨线程调用控件

Winform下: public delegate void UpadataTextCallBack(string str,TextBox text); public void UpadtaText(string str, TextBox text) { if (text.InvokeRequired) { UpadataTextCallBack upadataTextCallBack = UpadtaText; text.Invoke(upadataTextCallBack, new obje

跨线程调用控件 Invoke 与 BeginInvoke 区别

public delegate void Add_B(object x); List<object> Ls = new List<object>(); Ls.Add(i); Ls.Add("你好"); this.Invoke(new Action<object>(this.Add), Ls); //new Action<T>可以传递至多16种不合的参数类型. //例如:Action<in T1>调用带一个参数的办法,Actio

c# 跨线程调用控件的方法

Thread thread = new Thread(p=> { Action action = new Action(() => { System.Windows.Forms.MessageBox.Show("test"); }); action.Invoke(); }); thread.IsBackground = true; thread.Start();

C#跨线程操作控件的最简单实现探究

随着程序复杂度的提高,程序不可避免会出现多个线程,此时就很可能存在跨线程操作控件的问题. 跨线程操作UI控件主要有三类方式: 1.禁止系统的线程间操作检查.(此法不建议使用) 2.使用Invoke(同步)或者BeginInvoke(异步).(使用委托实现,并用lambda表达式简化代码) 3.使用BackgroundWorker组件.(此法暂不介绍,详情可见文末的参考资料) 先看一个跨线程操作失败的例子: 新建一个Winform窗口程序项目,拖一个button1和label1控件到Form1窗体

C# 跨线程操作控件方法封装

Winform程序需要处理耗时操作时,往往需要将耗时操作放入新开的子线程进行处理,在子线程中可能会经常去修改或操作主线程上的控件: 如果直接在子线程中操作控件,会报线程间操作无效等错误,这里提供一个我自己经常使用的跨线程操作方式,代码如下: //跨线程操作控件 //(将数据全部装填完毕后,在一起放到主界面刷新控件:不要一边装填一边刷新主界面控件,这样依然会导致界面卡顿) public void showMsg(string str) { if (textBox.InvokeRequired) {

2 跨线程访问控件InvokeHelper类

这里是一张动画,演示在多线程(无限循环+Thread.Sleep)情况下主界面操作不受影响. 多线程是一种提高程序运行效率和性能的常用技术.随着我们学习工作的深入,在编程中或多或少会涉及到需要多线程的情况.多数时候,我们的操作模式是后台线程中处理数据,计算结果,然后在前台界面(GUI)中更新显示. 在.NET Framework中,为了保证线程安全,避免出现访问竞争等问题,是不允许跨线程访问窗体控件的.如果强行访问,则会引发InvalidOperationException无效操作异常,如下图: