zoukankan      html  css  js  c++  java
  • 跨线程调用控件的几种方式

    一、问题描述

    有一个函数,它的功能就是加载数据,然后绑定到datagridview。现在开启一个线程去执行这个函数。结果可想而知,它会报错:提示线程无法访问。。。之类的话。为什么报错呢?因为你在开启的线程中操作了datagridview控件,也就是跨线程调用控件了。 那么我们应该怎么跨线程调用控件呢?跨线程调用控件的几种方法。

    二、解决方法

    1、方法一

    Control.CheckForIllegalCrossThreadCalls = false;这是通过禁止编译器检查对跨线程访问操作,但是这种方法不是安全的解决办法,尽量不要使用。代码下载:http://files.cnblogs.com/files/qtiger/CheckForIllegalCrossThreadCalls.rar。为什么说不安全呢?

    • 我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。
    • 一般对于跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了。

    2、方法二

    使用Delegate和Invoke跨线程调用控件(也叫代理方式),代码下载:http://files.cnblogs.com/files/qtiger/InvokeAndDelegate.zip

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

    在这里进行一下说明: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 事件与用户界面进行通信。

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

    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();
            }
        }
    }
  • 相关阅读:
    java学习笔记—ServletConfig、ServletContext接口(13)
    php中的XML DOM(11)
    php中的XML DOM(10)
    java学习笔记—Servlet技术(11)
    MM-移动类型
    MM-委外业务
    English-商务英文邮件例句100句
    ABAP-表中数据的横向累加
    MM-实际应用中的难题
    ABAP-加密解密
  • 原文地址:https://www.cnblogs.com/qtiger/p/5834320.html
Copyright © 2011-2022 走看看