C#后台线程和UI的交互

在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);
             }
         }
 
        <span style= "color: #ff0000;" ><strong> 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);
</strong></span>}

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

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值