C#中後臺線程和UI線程的交互

 在C#中,從Main()方法開始一個默認的線程,通常稱之爲主線程,若是在這個進行一些很是耗CPU的計算,那麼UI界面就會被掛起而處於假死狀態,也就是說沒法和用戶進行交互了,特別是要用相似進度條來實時顯示一些提示信息的時候,這種狀況就顯得很糟糕。若是多開一些線程來完成一些耗時的計算,那麼工做線程也是沒法如此更新UI界面中的元素的,好比直接顯示一個提示信息:label1.Text=outstring,緣由很簡單UI屬於默認的主線程,而線程間是不能這樣直接訪問彼此的成員的。
  若是要解決以上的兩個問題,那麼能夠藉助C#中的Delegate和控件類中的Invoke()方法來搞定。
  這裏給出的例子比較簡單,主要思路是:在Main()中啓動其它的線程做爲後臺進程,其中一個線程是實時顯示當前的時間,一個線程是顯示一些隨機數,這樣一來三個線程同時運行,彼此經過代理來聯繫。
  dom


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 );
        }


        #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)
        

        private void stop_Click(object sender, System.EventArgs e)
        

        private void pause_Click(object sender, System.EventArgs e)
        

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

相關文章
相關標籤/搜索