C# 採用系統委託方式處理線程內操做窗體控件

1、System.Windows.Forms.MethodInvoker 類型是一個系統定義的委託,用於調用不帶參數的方法。
  
  
  
  
private Thread myThread;

private void Form1_Load( object sender, EventArgs e)
{
myThread
= new Thread( new ThreadStart(RunsOnWorkerThread));
myThread.Start();
}

private void RunsOnWorkerThread()
{
MethodInvoker mi
= new MethodInvoker(SetControlsProp);
BeginInvoke(mi);
}

private void SetControlsProp()
{
label1.Text
= " myThread線程調用UI控件 " ;
}


2、直接用System.EventHandle(可帶參數)
 
  
  
  
  
private Thread myThread;

private void Form1_Load( object sender, EventArgs e)
{
myThread
= new Thread( new ThreadStart(RunsOnWorkerThread));
myThread.Start();
}

private void RunsOnWorkerThread()
{
// DoSomethingSlow();
string pList = " myThread線程調用UI控件 " ;
label1.BeginInvoke(
new System.EventHandler(UpdateUI), pList);
}

// 直接用System.EventHandler,沒有必要自定義委託
private void UpdateUI( object o, System.EventArgs e)
{
// UI線程設置label1屬性
label1.Text = o.ToString() + " 成功! " ;
}
包裝Control.Invoke
雖然第二個方法中的代碼解決了這個問題。但它很是煩瑣,若是輔助線程但願在結束的時候提供更多的反饋信息,而不是簡單地給出
"Finieshed!"消息,則BeginInvoke過於複雜的使用方法會使人剩畏。爲了傳達其餘消息,例如「正在處理」、「一切順利」等等,
須要設法向UpdateUI函數傳遞一個參數。可能還須要添加一個進度欄以提升反饋能力。這麼屢次調用BeginInvoke可能致使輔助線程
受該代碼支配,這樣不只會形成不便,並且考慮到輔助線程與UI的協調性,這樣設計也很差。對這些分析以後,咱們認爲包裝函數可
以解決這兩個問題
 private Thread myThread;
        private void Form1_Load(object sender, EventArgs e)
        {
            myThread = new Thread(new ThreadStart(RunOnWorkerThread));
            myThread.Start();
        }
 
        private void RunOnWorkerThread()
        {
            for (int i = 0; i < 100; i++)
            {
                showProgress(Convert.ToString(i), i);
                Thread.Sleep(100);
            }
        }
 

        public void showProgress(string msg, int percentDone)
        {
            System.EventArgs e = new MyProgressEvents(msg, percentDone);
            object[] pList = { this, e };
            BeginInvoke(new MyProgressEventsHandler(UpdateUI), pList);
        }
 
        private delegate void MyProgressEventsHandler(object sender, MyProgressEvents e);
        private void UpdateUI(object sender, MyProgressEvents e)
        {
            lblStatus.Text = e.Msg;
            myProgressControl.Value = e.PercentDone;
        }
 
        public class MyProgressEvents : EventArgs
        {
            public string Msg;
            public int PercentDone;
 
            public MyProgressEvents(string msg, int per)
            {
                Msg = msg;
                PercentDone = per;
            }
        }
ShowProgress方法對將調用引向正確線程的工做進行封裝。這意味着輔助線程代碼不用擔憂須要過多的關注UI細節,而只要按期調用
ShowProgress便可
若是我提供一個設計爲可從任何線程調用的公共方法,則徹底有可能某人會從UI線程調用這個方法。在這種狀況下,不必調用
BeginInvoke,由於我已經處於正確的線程中。調用Invoke徹底是浪費時間和資源,不如直接調用適當的方法。爲了不這個狀況,
Control類將公開一個稱爲InvokeRequired的屬性,這是「只限UI線程」規則的另外一個例外。它可從任何線程讀取,若是調用線程是
UI線程,則返回假,其餘線程則返回真。這覺得着:我能夠按如下方式修改包裝
 public void ShowProgress(string msg, int percentDone)
        {
            if (InvokeRequired)
            {

                //as before
                //..
            }
            else
            {
                //we're already on the UI thread just
                //call straight through
                UpdateUI(this, new MyProgressEventsHandler(msg, percentDone));
            }
        }





3、演示程序
              線程中調用部分:
結束。
    
    
    
    
// 初始化參數列表
List < String > paramList = new List < string > ();
paramList.Add(
" 0 " );
paramList.Add(
"" );

// 這裏採用系統委託的方式,實現線程內操做系統界面控件。
paramList[ 0 ] = " 0 " ; paramList[ 1 ] = " 清除屏幕信息 " ;
lstBoxCatchData.BeginInvoke(
new System.EventHandler(UpdateListBox),
paramList);
    
    
    
    
/// <summary>
/// 提供給系統委託事件調用,解決線程內操做界面控件的目的
/// </summary>
/// <param name="obj"></param>
/// <param name="e"></param>
private void UpdateListBox( object obj,System.EventArgs e)
{
// 強制類型轉換
List < String > paramList = (List < string > )obj;
if (paramList[ 0 ] == " 0 " )
{
this .lstBoxCatchData.Items.Clear();
}
else if (paramList[ 0 ] == " 1 " )
{
this .lstBoxCatchData.Items.Add(paramList[ 1 ].ToString()); } }