c#执行异步操做

转载自点击打开连接html

Winform中的控件是绑定到特定的线程的(通常是主线程),这意味着从另外一个线程更新主线程的控件不能直接调用该控件的成员。多线程

控件绑定到特定的线程这个概念以下:异步

为了从另外一个线程更新主线程的Windows Form控件,可用的方法有:ui

首先用一个简单的程序来示例,这个程序的功能是:在Winfrom窗体上,经过多线程用label显示时间。给出下面的两种实现方式spa

1.结合使用特定控件的以下成员                                            

InvokeRequired属性:返回一个bool值,指示调用者在不一样的线程上调用控件时是否必须使用Invoke()方法。若是主调线程不是建立该控件的线程,或者尚未为控件建立窗口句柄,则返回true。线程

Invoke()方法:在拥有控件的底层窗口句柄的线程上执行委托。代理

BeginInvoke()方法:异步调用Invoke()方法。code

EndInvoke()方法:获取BeginInvoke()方法启动的异步操做返回值。orm

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 MutipleThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
     

        public delegate void ChangeTimeDelegate(Control c);//包装代理类

        private void PrintTime()
        {
            if (label1.InvokeRequired == true)
            {
                
                while (true)
                {
                  label1.Invoke(new ChangeTimeDelegate((Control c)=> c.Text = DateTime.Now.ToString() ) , 
new object[] {label1});
                }
            }
            else
                while (true)
                {
                    label1.Text = DateTime.Today.ToString();
                }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(PrintTime));
t.IsBackground = true;
            t.Start(); 
        }

        
    }
}
还能够使用backegroundworker控件

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 MutipleThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
     

        public delegate void ChangeTimeDelegate(Control c);

        private void Form1_Load(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            if (label1.InvokeRequired == true)
            {

                while (true)
                {
                        label1.Invoke(new ChangeTimeDelegate((Control c) => c.Text = DateTime.Now.ToString())
                        , new object[] { label1 });
                }
            }
            else
                while (true)
                {
                    label1.Text = DateTime.Today.ToString();
                }
        }
    }
}
 
 

更新另外一个线程的进度条示例(第一种方法实现)                             

DebugLZQ以为第一种方法要更直观一点,或是更容易理解一点。下面再用第一种方法来作一个Demo:输入一个数,多线程计算其和值更新界面上的Label,并用进度条显示计算的进度。实际上就是,更新另外一个线程的两个UI控件。htm

原博客使用的是new 一个线程实现的,这里我是用backgroundworker组件实现

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 MutipleThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
     

        public delegate void ChangeProgressDelegate(ProgressBar c,int s);
        public delegate void ChangeLabelDelegate(Control c, string s);
     

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            long num = Convert.ToInt64(e.Argument);
            long sum = 0;
            for(long i = 1; i <= num; i++)
            {
                sum += i;
                if(i % 100 == 0)
                {
                    
                        progressBar1.Invoke(new ChangeProgressDelegate((ProgressBar c,int s) => c.Value = s),
                        new object[] { progressBar1, Convert.ToInt32((i * 100) / num) });
                    
                }
                
                
            }
            label1.Invoke(new ChangeLabelDelegate((Control c, string s) =>
            {
                c.Text = s;
            }), new object[] { label1, sum.ToString() });
        }

        private void button1_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync(textBox1.Text);
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar1.Value = 0;
            textBox1.Text = "";
        }
    }
}
总以为这样更新一个组件太麻烦了,又是代理进程的。不知道还有没有更好的办法。继续研究一下