C#後台線程和UI的互動

來源:互聯網
上載者:User

在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  的例子. 

  

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.