.NET一个线程更新另一个线程的UI(两种实现方法)
[来源] 达内 [编辑] 达内 [时间]2012-11-13
Winform中的控件是绑定到特定的线程的(一般是主线程),这意味着从另一个线程更新主线程的控件不能直接调用该控件的成员
Winform中的控件是绑定到特定的线程的(一般是主线程),这意味着从另一个线程更新主线程的控件不能直接调用该控件的成员。
控件绑定到特定的线程这个概念如下:
为了从另一个线程更新主线程的Windows Form控件,可用的方法有:
首先用一个简单的程序来示例,这个程序的功能是:在Winfrom窗体上,通过多线程用label显示时间。给出下面的两种实现方式
1.结合使用特定控件的如下成员
InvokeRequired属性:返回一个bool值,指示调用者在不同的线程上调用控件时是否必须使用Invoke()方法。如果主调线程不是创建该控件的线程,或者还没有为控件创建窗口句柄,则返回true。
Invoke()方法:在拥有控件的底层窗口句柄的线程上执行委托。
BeginInvoke()方法:异步调用Invoke()方法。
EndInvoke()方法:获取BeginInvoke()方法启动的异步操作返回值。
using System; using System.Collections.Generic; using System.ComponentModel; using ; using System.Drawing; using System.Linq; using System.Text; using .Forms; using System.Threading; namespace 一个线程更新另一个线程UI2 { /// <summary> /// DebugLZQ /// /// </summary> public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void UpdateLabel(Control ctrl, string s) { ctrl.Text = s; } private delegate void UpdateLabelDelegate(Control ctrl, string s); private void PrintTime() { if (label1.InvokeRequired == true ) { UpdateLabelDelegate uld = new UpdateLabelDelegate(UpdateLabel); while (true ) { label1.Invoke(uld, new object [] { label1, .ToString() }); } } else { while (true ) { label1.Text = .ToString(); } } } private void Form1_Load(object sender, EventArgs e) { //PrintTime(); //错误的单线程调用 Thread t = new Thread(new ThreadStart(PrintTime)); t.Start(); } } }
比较和BackgroundWorker控件方式的异同点。
2.使用BackgroundWorker控件。
using System; using System.Collections.Generic; using System.ComponentModel; using ; using System.Drawing; using System.Linq; using System.Text; using .Forms; namespace 一个线程更新另一个线程UI { /// <summary> /// DebugLZQ /// /// </summary> public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void UpdateLabel(Control ctrl, string s) { ctrl.Text = s; } private delegate void UpdateLabelDelegate(Control ctrl, string s); private void PrintTime() { if (label1.InvokeRequired == true ) { UpdateLabelDelegate uld = new UpdateLabelDelegate(UpdateLabel); while (true ) { label1.Invoke(uld, new object [] { label1, .ToString() }); } } else { while (true ) { label1.Text = .ToString(); } } } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { PrintTime(); } private void Form1_Load(object sender, EventArgs e) { backgroundWorker1.RunWorkerAsync(); } } }
程序的运行结果如下:
更新另一个线程的进度条示例(第一种方法实现)
DebugLZQ觉得第一种方法要更直观一点,或是更容易理解一点。下面再用第一种方法来做一个Demo:输入一个数,多线程计算其和值更新界面上的Label,并用进度条显示计算的进度。实际上就是,更新另一个线程的两个UI控件。
using System; using System.Collections.Generic; using System.ComponentModel; using ; using System.Drawing; using System.Linq; using System.Text; using .Forms; using System.Threading; namespace 一个线程更新另一个线程的UI3 { /// <summary> /// DebugLZQ /// /// </summary> public partial class Form1 : Form { public Form1() { InitializeComponent(); } private static long result = 0 ; // 更新Label private void UpdateLabel(Control ctrl, string s) { ctrl.Text = s; } private delegate void UpdateLabelDelegate(Control ctrl, string s); // 更新ProgressBar private void UpdateProgressBar(ProgressBar ctrl, int n) { ctrl.Value = n; } private delegate void UpdateProgressBarDelegate(ProgressBar ctrl, int n); private void Sum(object o) { result = 0 ; long num = Convert.ToInt64(o); UpdateProgressBarDelegate upd = new UpdateProgressBarDelegate(UpdateProgressBar); for (long i = 1 ; i <= num; i++) { result += i; //更新ProcessBar1 if (i % 10000 == 0)// 这个数值要选的合适,太小程序会卡死 { if (progressBar1.InvokeRequired == true ) { progressBar1.Invoke(upd, new object [] { progressBar1, Convert.ToInt32((100 * i) / num) });// 若是(i/num)*100,为什么进度条会卡滞? } else { progressBar1.Value = Convert.ToInt32(i / num * 100 ); } } } // 更新lblResult if (lblResult.InvokeRequired == true ) { UpdateLabelDelegate uld = new UpdateLabelDelegate(UpdateLabel); lblResult.Invoke(uld, new object [] { lblResult, result.ToString() }); } else { lblResult.Text = result.ToString(); } } private void btnStart_Click(object sender, EventArgs e) { Thread t = new Thread(new ParameterizedThreadStart(Sum)); t.Start(txtNum.Text); } } }
程序的运行结果如下:
用BackgroundWorker控件可以实现相同的功能,个人觉得这样更容易理解~