C#后台线程和UI的交互
http://www.cnblogs.com/Wizardh/articles/963097.html
?
?在C#中,從Main()方法開始一個默認的線程,一般稱之為主線程,如果在這個進行一些非常耗CPU的計算,那么UI界面就會被掛起而處于假死狀態,也就是說無法和用戶進行交互了,特別是要用類似進度條來實時顯示一些提示信息的時候,這種情況就顯得很糟糕。如果多開一些線程來完成一些耗時的計算,那么工作線程也是無法如此更新UI界面中的元素的,比如直接顯示一個提示信息:label1.Text=outstring,原因很簡單UI屬于默認的主線程,而線程間是不能這樣直接訪問彼此的成員的。
??如果要解決以上的兩個問題,那么可以借助C#中的Delegate和控件類中的Invoke()方法來搞定。
??這里給出的例子比較簡單,主要思路是:在Main()中啟動其它的線程作為后臺進程,其中一個線程是實時顯示當前的時間,一個線程是顯示一些隨機數,這樣一來三個線程同時運行,彼此通過代理來聯系。
??
using?System;
using?System.Drawing;
using?System.Collections;
using?System.ComponentModel;
using?System.Windows.Forms;
using?System.Data;
using?System.Threading;
namespace?MutliThreadedWinFormsApp
{
????public?class?Form1?:?System.Windows.Forms.Form
????{
????????private?Thread?currentTimeThread?=?null;
????????private?Thread?randomNumbersThread?=?null;
????????private?System.Windows.Forms.Label?label1;
????????private?System.Windows.Forms.TextBox?currentTime;
????????private?System.Windows.Forms.Label?label2;
????????private?System.Windows.Forms.TextBox?randomNumbers;
????????private?System.Windows.Forms.GroupBox?threadManager;
????????private?System.Windows.Forms.Button?pause;
????????private?System.Windows.Forms.Button?stop;
????????private?System.Windows.Forms.Button?start;
????????private?System.Windows.Forms.RadioButton?manageTime;
????????private?System.Windows.Forms.RadioButton?manageNumbers;
????????private?System.Windows.Forms.RadioButton?manageBoth;
????????private?System.ComponentModel.Container?components?=?null;
????????public?Form1()
????????{
????????????InitializeComponent();
????????????
????????????//創建新的工作線程
????????????currentTimeThread?=?new?Thread(new?ThreadStart(CountTime));
????????????currentTimeThread.IsBackground?=?true;
????????????
????????????randomNumbersThread?=?new?Thread(new?ThreadStart(GenerateRandomNumbers));
????????????randomNumbersThread.IsBackground?=?true;
????????}
????????protected?override?void?Dispose(?bool?disposing?)
????????{
????????????if(?disposing?)
????????????{
????????????????if?(components?!=?null)?
????????????????{
????????????????????components.Dispose();
????????????????}
????????????}
????????????base.Dispose(?disposing?);
????????}
????????UI設計#region?UI設計
????????private?void?InitializeComponent()
????????{
????????????this.label1?=?new?System.Windows.Forms.Label();
????????????this.currentTime?=?new?System.Windows.Forms.TextBox();
????????????this.label2?=?new?System.Windows.Forms.Label();
????????????this.randomNumbers?=?new?System.Windows.Forms.TextBox();
????????????this.threadManager?=?new?System.Windows.Forms.GroupBox();
????????????this.manageBoth?=?new?System.Windows.Forms.RadioButton();
????????????this.manageNumbers?=?new?System.Windows.Forms.RadioButton();
????????????this.manageTime?=?new?System.Windows.Forms.RadioButton();
????????????this.pause?=?new?System.Windows.Forms.Button();
????????????this.stop?=?new?System.Windows.Forms.Button();
????????????this.start?=?new?System.Windows.Forms.Button();
????????????this.threadManager.SuspendLayout();
????????????this.SuspendLayout();
????????????//?
????????????//?label1
????????????//?
????????????this.label1.AutoSize?=?true;
????????????this.label1.Location?=?new?System.Drawing.Point(8,?24);
????????????this.label1.Name?=?"label1";
????????????this.label1.Size?=?new?System.Drawing.Size(79,?13);
????????????this.label1.TabIndex?=?0;
????????????this.label1.Text?=?"現在的時間:";
????????????//?
????????????//?currentTime
????????????//?
????????????this.currentTime.Location?=?new?System.Drawing.Point(88,?23);
????????????this.currentTime.Name?=?"currentTime";
????????????this.currentTime.ReadOnly?=?true;
????????????this.currentTime.Size?=?new?System.Drawing.Size(157,?20);
????????????this.currentTime.TabIndex?=?1;
????????????//?
????????????//?label2
????????????//?
????????????this.label2.AutoSize?=?true;
????????????this.label2.Location?=?new?System.Drawing.Point(14,?56);
????????????this.label2.Name?=?"label2";
????????????this.label2.Size?=?new?System.Drawing.Size(43,?13);
????????????this.label2.TabIndex?=?2;
????????????this.label2.Text?=?"隨機數";
????????????//?
????????????//?randomNumbers
????????????//?
????????????this.randomNumbers.Location?=?new?System.Drawing.Point(16,?72);
????????????this.randomNumbers.Name?=?"randomNumbers";
????????????this.randomNumbers.ReadOnly?=?true;
????????????this.randomNumbers.Size?=?new?System.Drawing.Size(229,?20);
????????????this.randomNumbers.TabIndex?=?3;
????????????//?
????????????//?threadManager
????????????//?
????????????this.threadManager.Controls.Add(this.manageBoth);
????????????this.threadManager.Controls.Add(this.manageNumbers);
????????????this.threadManager.Controls.Add(this.manageTime);
????????????this.threadManager.Controls.Add(this.pause);
????????????this.threadManager.Controls.Add(this.stop);
????????????this.threadManager.Controls.Add(this.start);
????????????this.threadManager.Location?=?new?System.Drawing.Point(16,?104);
????????????this.threadManager.Name?=?"threadManager";
????????????this.threadManager.Size?=?new?System.Drawing.Size(229,?154);
????????????this.threadManager.TabIndex?=?7;
????????????this.threadManager.TabStop?=?false;
????????????this.threadManager.Text?=?"工作線程控制";
????????????//?
????????????//?manageBoth
????????????//?
????????????this.manageBoth.Location?=?new?System.Drawing.Point(34,?74);
????????????this.manageBoth.Name?=?"manageBoth";
????????????this.manageBoth.Size?=?new?System.Drawing.Size(104,?16);
????????????this.manageBoth.TabIndex?=?12;
????????????this.manageBoth.Text?=?"同時運行";
????????????this.manageBoth.CheckedChanged?+=?new?System.EventHandler(this.manageBoth_CheckedChanged);
????????????//?
????????????//?manageNumbers
????????????//?
????????????this.manageNumbers.Location?=?new?System.Drawing.Point(34,?50);
????????????this.manageNumbers.Name?=?"manageNumbers";
????????????this.manageNumbers.Size?=?new?System.Drawing.Size(104,?16);
????????????this.manageNumbers.TabIndex?=?11;
????????????this.manageNumbers.Text?=?"更新隨機數線程";
????????????this.manageNumbers.CheckedChanged?+=?new?System.EventHandler(this.manageNumbers_CheckedChanged);
????????????//?
????????????//?manageTime
????????????//?
????????????this.manageTime.Location?=?new?System.Drawing.Point(34,?26);
????????????this.manageTime.Name?=?"manageTime";
????????????this.manageTime.Size?=?new?System.Drawing.Size(104,?16);
????????????this.manageTime.TabIndex?=?10;
????????????this.manageTime.Text?=?"更新時間線程";
????????????this.manageTime.CheckedChanged?+=?new?System.EventHandler(this.manageTime_CheckedChanged);
????????????//?
????????????//?pause
????????????//?
????????????this.pause.Location?=?new?System.Drawing.Point(84,?115);
????????????this.pause.Name?=?"pause";
????????????this.pause.Size?=?new?System.Drawing.Size(54,?23);
????????????this.pause.TabIndex?=?9;
????????????this.pause.Text?=?"暫停";
????????????this.pause.Click?+=?new?System.EventHandler(this.pause_Click);
????????????//?
????????????//?stop
????????????//?
????????????this.stop.Location?=?new?System.Drawing.Point(158,?115);
????????????this.stop.Name?=?"stop";
????????????this.stop.Size?=?new?System.Drawing.Size(51,?23);
????????????this.stop.TabIndex?=?8;
????????????this.stop.Text?=?"停止";
????????????this.stop.Click?+=?new?System.EventHandler(this.stop_Click);
????????????//?
????????????//?start
????????????//?
????????????this.start.Location?=?new?System.Drawing.Point(6,?115);
????????????this.start.Name?=?"start";
????????????this.start.Size?=?new?System.Drawing.Size(50,?23);
????????????this.start.TabIndex?=?7;
????????????this.start.Text?=?"開始";
????????????this.start.Click?+=?new?System.EventHandler(this.start_Click);
????????????//?
????????????//?Form1
????????????//?
????????????this.AutoScaleBaseSize?=?new?System.Drawing.Size(5,?13);
????????????this.ClientSize?=?new?System.Drawing.Size(253,?271);
????????????this.Controls.Add(this.threadManager);
????????????this.Controls.Add(this.randomNumbers);
????????????this.Controls.Add(this.label2);
????????????this.Controls.Add(this.currentTime);
????????????this.Controls.Add(this.label1);
????????????this.Name?=?"Form1";
????????????this.Text?=?"工作線程和UI的交互";
????????????this.Closing?+=?new?System.ComponentModel.CancelEventHandler(this.Form1_Closing);
????????????this.threadManager.ResumeLayout(false);
????????????this.ResumeLayout(false);
????????????this.PerformLayout();
????????}
????????#endregion
????????
????????[STAThread]
????????static?void?Main()?
????????{
????????????Application.Run(new?Form1());
????????}
????????private?void?start_Click(object?sender,?System.EventArgs?e)
????????{
????????????bool?bTime?=?false,?bRandomNumbers?=?false;
????????????if(?manageTime.Checked?||?manageBoth.Checked?)
????????????????bTime?=?true;
????????????if(?manageNumbers.Checked?||?manageBoth.Checked?)
????????????????bRandomNumbers?=?true;
????????????if(?bTime?)
????????????????currentTimeThread.Start();
????????????
????????????if(?bRandomNumbers?)
????????????????randomNumbersThread.Start();
????????????start.Enabled?=?false;
????????????stop.Enabled?=?true;
????????????pause.Enabled?=?true;
????????}
????????private?void?stop_Click(object?sender,?System.EventArgs?e)
????????{
????????????bool?bTime?=?false,?bRandomNumbers?=?false;
????????????if(?manageTime.Checked?==?true?||?manageBoth.Checked?==?true?)
????????????????bTime?=?true;
????????????if(?manageNumbers.Checked?==?true?||?manageBoth.Checked?==?true?)
????????????????bRandomNumbers?=?true;
????????????if(?bTime?)
????????????{
????????????????currentTimeThread.Abort();
????????????????currentTimeThread.Join();
????????????????currentTimeThread?=?new?Thread(new?ThreadStart(CountTime));
????????????????currentTimeThread.IsBackground?=?true;
????????????}
????????????if(?bRandomNumbers?)
????????????{
????????????????randomNumbersThread.Abort();
????????????????randomNumbersThread.Join();
????????????????randomNumbersThread?=?new?Thread(new?ThreadStart(GenerateRandomNumbers));
????????????????randomNumbersThread.IsBackground?=?true;
????????????}
????????????start.Enabled?=?true;
????????????stop.Enabled?=?false;
????????????pause.Enabled?=?false;
????????}
????????private?void?pause_Click(object?sender,?System.EventArgs?e)
????????{
????????????bool?bTime?=?false,?bRandomNumbers?=?false;
????????????if(?manageTime.Checked?==?true?||?manageBoth.Checked?==?true?)
????????????????bTime?=?true;
????????????if(?manageNumbers.Checked?==?true?||?manageBoth.Checked?==?true?)
????????????????bRandomNumbers?=?true;
????????????if(?bTime?)
????????????{
????????????????if(?0?!=?(currentTimeThread.ThreadState?&?(?ThreadState.Suspended?|?ThreadState.SuspendRequested?)?)?)
????????????????????currentTimeThread.Resume();
????????????????else
????????????????????currentTimeThread.Suspend();
????????????}
????????????if(?bRandomNumbers?)
????????????{
????????????????if(?0?!=?(randomNumbersThread.ThreadState?&?(?ThreadState.Suspended?|?ThreadState.SuspendRequested?)?)?)
????????????????????randomNumbersThread.Resume();
????????????????else
????????????????????randomNumbersThread.Suspend();
????????????}
????????}
????????private?void?manageTime_CheckedChanged(object?sender,?System.EventArgs?e)
????????{
????????}
????????private?void?manageNumbers_CheckedChanged(object?sender,?System.EventArgs?e)
????????{
????????}
????????private?void?manageBoth_CheckedChanged(object?sender,?System.EventArgs?e)
????????{
????????}
????????/**////?<summary>
????????///?注意其Invoke的使用,其有兩種使用形式
????????///?public?void?Invoke(System.Delegate?delegate);
????????///?public?void?Invoke(System.Delegate?delegate,?object?[]?args);
????????///?</summary>
????????public?void?CountTime()
????????{
????????????while(true)
????????????{
????????????????Invoke(new?UpdateTimeDelegate(updateCurrentTime));
????????????????Thread.Sleep(1000);
????????????}
????????}
????????public?void?GenerateRandomNumbers()
????????{
????????????int?[]?randomNumbers?=?new?int[10];
????????????Random?r?=?new?Random();
????????????while(true)
????????????{
????????????????for(int?i?=?0;?i?<?randomNumbers.Length;?i++)
????????????????????randomNumbers[i]?=?r.Next(1,?100);
????????????????Invoke(new?UpdateRandomNumbers(updateRandomNumbers),?new?object[]?{?randomNumbers?});
????????????????Thread.Sleep(500);
????????????}
????????}
????????/**////?<summary>
????????///?負責更新UI界面中時間顯示的函數
????????///?</summary>
????????private?void?updateCurrentTime()
????????{
????????????currentTime.Text?=?DateTime.Now.ToLongTimeString();
????????}
????????
????????/**////?<summary>
????????///?負責更新UI界面中隨機數顯示的函數
????????///?</summary>
????????///?<param?name="numbers"></param>
????????private?void?updateRandomNumbers(int?[]?numbers)
????????{
????????????System.Text.StringBuilder?sb?=?new?System.Text.StringBuilder();
????????????foreach(int?i?in?numbers)
????????????????sb.Append(i.ToString()).Append(",?");
????????????randomNumbers.Text?=?sb.ToString();
????????}
????????private?void?Form1_Closing(object?sender,?System.ComponentModel.CancelEventArgs?e)
????????{
????????????if(?(randomNumbersThread.ThreadState?&?ThreadState.Running)?==?ThreadState.Running?)
????????????????randomNumbersThread.Abort();
????????????randomNumbersThread?=?null;
????????????
????????????if(?(currentTimeThread.ThreadState?&?ThreadState.Running)?==?ThreadState.Running?)
????????????????currentTimeThread.Abort();
????????????currentTimeThread?=?null;
????????}
????}
????public?delegate?void?UpdateTimeDelegate();
????public?delegate?void?UpdateRandomNumbers(int?[]?numbers);
}
?? 其實在C# 2.0 中所有的Control類都有Invoke()方法,如果負責更新UI元素的函數不是定義在Main()中,那么必須首先檢測Control類中的InvokeRequired屬性。舉個例子吧,注意setProgressBarValue()函數中調用自己的方式.
??????? //在工作線程中更新主窗口進度條
??????? public void setProgressBarValue(ProgressBar progressBar1,int value)
??????? {
??????????? if (progressBar1.InvokeRequired)
??????????? {
??????????????? object[] parameters = new object[] { value };
??????????????? progressBar1.Invoke(new setProgressBarValueDelegate(setProgressBarValue), parameters);
??????????? }
??????????? else
??????????????? progressBar1.Value = value;
??????? }
? 這里的一些代碼參考了http://www.codeproject.com? 的例子.
轉載于:https://www.cnblogs.com/l1b2q31/articles/2195708.html
總結
以上是生活随笔為你收集整理的C#后台线程和UI的交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 由树先序遍历和中序遍历输出其后续遍历
- 下一篇: 找到两个字符串的公共字符,并按照其中一个