• BackGroundWorker组件使用、Winform控件的Invoke安全调用


    BackgroundWorker是·net里用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。

    可以通过编程方式创建 BackgroundWorker,也可以将它从“工具箱”的“组件”选项卡中拖到窗体上。 如果在 Windows 窗体设计器中创建 BackgroundWorker,则它会出现在组件栏中,而且它的属性会显示在“属性”窗口中。

    常用方法

    1. RunWorkerAsync 开始执行后台操作。引发 DoWork 事件。
         public void RunWorkerAsync(); //启动线程,触发DoWork事件
         public void RunWorkerAsync(object argument);
    2. CancelAsync 请求取消挂起的后台操作。
      注意:这个方法是将 CancellationPending 属性设置为 true,并不会终止后台操作。在后台操作中要检查CancellationPending 属性,来决定是否要继续执行耗时的操作。
    3. ReportProgress引发 ProgressChanged 事件。
         public void ReportProgress(int percentProgress); //报告进度,触发ProgressChanged事件
         public void ReportProgress(int percentProgress, object userState);

    常用属性

    1. IsBusy:  //只读属性,用来判断当前线程是否正在工作中。
    2. CancellationPending: 指示应用程序是否已请求取消后台操作。只读属性,默认为 false,当执行了 CancelAsync 方法后,值为 true。
    3. WorkerSupportsCancellation:指示是否支持异步取消。要执行 CancelAsync 方法,需要先设置该属性为 true。
    4. WorkerReportsProgress:指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。

    常用事件

    1. DoWork: 调用 RunWorkerAsync 方法时发生。
    2. ProgressChanged:可选,调用 ReportProgress 方法时发生。
    3. RunWorkerCompleted:可选,后台操作已完成、被取消或引发异常时发生。

    注意:在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和RunWorkerCompleted 事件与用户界面进行通信。

      如果想在 DoWork 事件处理程序中和用户界面的控件通信,可在用 ReportProgress 方法。ReportProgress(int percentProgress, object userState),可以传递一个对象。ProgressChanged 事件可以从参数ProgressChangedEventArgs 类的UserState 属性得到这个信息对象。这个事件也可以实现进度条功能,把任务的进度实时呈现给用户。

    简单的程序用BackgroundWorker 比 Thread 方便,Thread中和用户界面上的控件通信比较麻烦,需要用委托来调用控件的 Invoke 或BeginInvoke 方法,没有 BackgroundWorker 方便。

    使用backgroundWorker步骤

    • 新建BackgroundWorder对象;

    • 根据需求, 设置是否能取消(WorkerSupportsCancellation)、是否报告进度(WorkerReportsProgress);

    • 根据需求,设置好相关事件,DoWorker、ProgressChanged、ProgressChanged;

    • 调用RunWorkerAsyns()方法,启动线程;

    • 在需要取消的位置,判断CancellationPending的值,并做相关处理;//可选

    • 在适当的位置调用ReportProgress(int percentProgress)方法,报告进度。

    BackgroundWorker实例

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                backgroundWorker1.WorkerReportsProgress = true;//报告完成进度
                backgroundWorker1.WorkerSupportsCancellation = true;//允许用户终止后台线程
                                                                    //绑定事件
                backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
                backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
                backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
    
            }
            //开始按钮
            private void button1_Click(object sender, EventArgs e)
            {
                if (!backgroundWorker1.IsBusy)//判断backgroundWorker1是否正在运行异步操作
                {
                    backgroundWorker1.RunWorkerAsync(1000);//开始执行后台异步操作,调用DoWork事件
                }
                while (backgroundWorker1.IsBusy)//等待后台运行完毕
                {
                    Application.DoEvents();
                }
                MessageBox.Show("操作完成");
            }
    
            //取消按钮
            private void button2_Click(object sender, EventArgs e)
            {
                if (backgroundWorker1.WorkerSupportsCancellation == true)
                {
                    backgroundWorker1.CancelAsync();//取消后台操作
                    backgroundWorker1.Dispose();//释放资源
                }
            }
    
            //DoWork事件声明要执行的耗时操作
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker backgroundWorker = sender as BackgroundWorker;
                e.Result = ListNumber(backgroundWorker, e);//运算结果保存在e.Result中(在RunWorkerCompleted事件可能会使用到)
            }
    
            bool ListNumber(object sender, DoWorkEventArgs e)
            {
                int num = (int)e.Argument;//接收传入的参数,即RunWorkerAsync(object argument)传入的值
                for (int i = 1; i <= num; i++)
                {
                    if (backgroundWorker1.CancellationPending)//判断是否请求了取消后台操作,如果为false则退出
                    {
                        e.Cancel = true;//e.Cancel 是否应该取消事件
                        return false;
                    }
                    Thread.Sleep(10);//执行一个耗时操作
                    backgroundWorker1.ReportProgress(i * 100 / num, i);//报告完成进度
    
                }
                return true;
            }
    
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
    
                progressBar1.Value = e.ProgressPercentage;//将完成进度数据传给进度条
                label1.Text = e.ProgressPercentage + "%";
                //将中间计算结果在ListBox控件中显示出来
                listBox1.Items.Add(e.UserState);//接收ReportProgress方法传递过来的userState
            }
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e.Cancelled == true) //e.Cancelled指示异步操作是否已被取消
                {
                    MessageBox.Show("Canceled!");
                }
                else if (e.Error != null) //e.Error 指示异步操作期间发生的错误
                {
                    MessageBox.Show("Error: " + e.Error.Message);
                }
                else
                {
                    MessageBox.Show(e.Result.ToString());  //e.Result 获取异步操作结果的值,即DoWork事件中,Result设置的值。
                }
    
            }
        }

    对Winform窗体控件进行安全调用

    (WinForm中实现多线程的首选方法是backgroundWorker)

    Thread thread = new Thread(SetLabel);//另开一个线程上设置Label的属性
    thread.Start();
     
    delegate void Action(string args);//Net3.5自带的Action无参数无返回值
    private void SetLabel()
    {
        Action action = delegate (string args)
        {
            this.label1.Text = args;
        };
        if (this.InvokeRequired)//判断当前代码是运行于创建该控件的线程之上,还是运行于另一个线程之上。
            this.Invoke(action, "XXX");//注意控件的Inovoke和BeginInvoke委托的方法都执行在UI线程上。对Control的Invoke方法可以使用一个简单的系统委托MethodInvoker无参数返回Void调用。
        else
            action("XXX");
    }
  • 相关阅读:
    扫描线算法模板
    spark submit 常用设置
    networkx 画有向图 使用DiGraph
    超实用的Spark数据倾斜解决
    解决spark中遇到的数据倾斜问题
    TrickBot 恶意木马软件
    windows 打开snappy文件 安装python snappy——还是直接用pip install xx.whl 打包好的安装吧
    解决CentOS删除文件后没有释放磁盘空间(lsof命令)
    Linux 系统下 centOS 7 ipconfig 提示没有安装
    tomcat启动报错org.apache.catalina.LifecycleException: The configured protocol [org.apache.coyote.http...
  • 原文地址:https://www.cnblogs.com/springsnow/p/9428817.html
Copyright © 2020-2023  润新知