.NET一个线程更新另一个线程的UI(两种实现方法)

[来源] 达内    [编辑] 达内   [时间]2012-11-13

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

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

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">控件绑定到特定的线程这个概念如下:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">为了从另一个线程更新主线程的Windows Form控件,可用的方法有:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> 首先用一个简单的程序来示例,这个程序的功能是:在Winfrom窗体上,通过多线程用label显示时间。给出下面的两种实现方式

< h2 style="margin: 15px auto 2px; padding: 0px; font-size: 18px; font-weight: bold; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-style: normal; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> 1.结合使用特定控件的如下成员                                             < p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> InvokeRequired属性:返回一个bool值,指示调用者在不同的线程上调用控件时是否必须使用Invoke()方法。如果主调线程不是创建该控件的线程,或者还没有为控件创建窗口句柄,则返回true。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">Invoke()方法:在拥有控件的底层窗口句柄的线程上执行委托。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">BeginInvoke()方法:异步调用Invoke()方法。

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">EndInvoke()方法:获取BeginInvoke()方法启动的异步操作返回值。

< div style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); font-family: 'Courier New'; font-size: 12px; border: 1px solid rgb(204, 204, 204); overflow: auto; color: rgb(85, 85, 85); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; " class="cnblogs_code">
using
 System; using
 System.Collections.Generic; 
using

 System.ComponentModel; using
 System.Data; using
 System.Drawing; using
 System.Linq; using
 System.Text; using
 System.Windows.Forms; using
 System.Threading;  namespace
 一个线程更新另一个线程UI2 {     
///

 <summary>

    /// DebugLZQ     
/// 
http://www.cnblogs.com/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, DateTime.Now.ToString() });                 }             }             
else
             {                 

while (true
)                 {                     label1.Text 
= DateTime.Now.ToString();                 }             }         }          

private void
 Form1_Load(object
 sender, EventArgs e)         {             

//PrintTime();
//错误的单线程调用

             Thread t = new
 Thread(new
 ThreadStart(PrintTime));             t.Start();         }     } }
< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">比较和BackgroundWorker控件方式的异同点。

< h2 style="margin: 15px auto 2px; padding: 0px; font-size: 18px; font-weight: bold; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-style: normal; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> 2.使用BackgroundWorker控件。                                < div style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); font-family: 'Courier New'; font-size: 12px; border: 1px solid rgb(204, 204, 204); overflow: auto; color: rgb(85, 85, 85); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; " class="cnblogs_code">
using
 System; using
 System.Collections.Generic; 
using

 System.ComponentModel; using
 System.Data; using
 System.Drawing; using
 System.Linq; using
 System.Text; using
 System.Windows.Forms;  
namespace

 一个线程更新另一个线程UI {     
///

 <summary>

    /// DebugLZQ     
/// 
http://www.cnblogs.com/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, DateTime.Now.ToString() });                 }             }             
else
             {                 

while (true
)                 {                     label1.Text 
= DateTime.Now.ToString();                 }             }         }          

private void
 backgroundWorker1_DoWork(object
 sender, DoWorkEventArgs e)         {             PrintTime();         }          private
 void Form1_Load(object
 sender, EventArgs e)         {             backgroundWorker1.RunWorkerAsync();         }     } }
< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">程序的运行结果如下:

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">

< h2 style="margin: 15px auto 2px; padding: 0px; font-size: 18px; font-weight: bold; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-style: normal; font-variant: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> 更新另一个线程的进度条示例(第一种方法实现)                              < p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> DebugLZQ觉得第一种方法要更直观一点,或是更容易理解一点。下面再用第一种方法来做一个Demo:输入一个数,多线程计算其和值更新界面上的Label,并用进度条显示计算的进度。实际上就是,更新另一个线程的两个UI控件。

< div style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); font-family: 'Courier New'; font-size: 12px; border: 1px solid rgb(204, 204, 204); overflow: auto; color: rgb(85, 85, 85); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; " class="cnblogs_code">
using
 System; using
 System.Collections.Generic; 
using

 System.ComponentModel; using
 System.Data; using
 System.Drawing; using
 System.Linq; using
 System.Text; using
 System.Windows.Forms; using
 System.Threading;  namespace
 一个线程更新另一个线程的UI3 {     
///

 <summary>

    /// DebugLZQ     
/// 
http://www.cnblogs.com/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);         }          } }
< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">程序的运行结果如下: 

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); ">

< p style="margin: 10px auto; padding: 0px; text-indent: 0px; color: rgb(85, 85, 85); font-family: verdana, 'ms song', 宋体, Arial, 微软雅黑, Helvetica, sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 24px; orphans: 2; text-align: left; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-color: rgb(245, 248, 250); "> 用BackgroundWorker控件可以实现相同的功能,个人觉得这样更容易理解~

资源下载