一、知識點介紹
1,更新控件的內容,應該調用控件的Invoke方法。
Invoke指: 在擁有控件的基礎窗口句柄的線程上,用指定的參數列表執行指定委托。該方法接收一個委托類型和委托的參數,因此需要定義委托類型變量,然后傳遞給Invoke方法。
如果其他線程直接調用方法更新控件內容,報錯:線程間操作無效: 從不是創建控件“richTextBox1”的線程訪問它。
2,委托的本質是某一類型的方法,這些方法具有相同的參數和返回類型。
委托類似於C語言中的函數指針,可以指向多個相同類型的函數。
定義委托,只需要在函數返回類型前加上delegate關鍵詞,把函數體大括號{}的內容換成分號即可。比如:
public delegate void DelegateFun(string msg);
DelegateFun就代表了一個函數類型,它接收string參數,返回void。
3,開辟一個線程,直接啟動,后面通過掛起和喚醒實現暫停功能。
Thread t = new Thread(Run);
t.Start(); // 啟動
通過判斷線程狀態,決定是否喚醒線程。
if (t.ThreadState == ThreadState.Suspended) // 如果被掛起了,就喚醒
{
t.Resume();
}
暫停就掛起線程:
t.Suspend(); // 停止,掛起線程
注:也可以定義一個開關,用來控制開始和結束,在開關為false的時候,直接continue,這樣表現為暫停輸出,但是實際上線程一直在運行。
二、界面和代碼

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication3 { public partial class Form2 : Form { public Form2() { InitializeComponent(); } /// <summary> /// 因為控件的Invoke方法需要接收委托變量,因此需要定義委托和委托變量 /// 定義一個委托,接收一個參數 /// </summary> /// <param name="msg"></param> public delegate void DelegateFun(string msg); /// <summary> /// 定義一個委托變量 /// 這個委托變量,需要初始化指定具體的方法;然后傳遞給控件的Invoke方法調用。 /// </summary> public DelegateFun Fun1; /// <summary> /// 定義一個線程,處理數據,並更新界面 /// </summary> private Thread t = null; // 開始按鈕 private void button1_Click(object sender, EventArgs e) { this.Invoke(Fun1, "開始..."); // 增加判斷,避免每次單擊都開辟一個線程 if (t == null) { t = new Thread(Run); t.Start(); } if (t.ThreadState == ThreadState.Suspended) // 如果被掛起了,就喚醒 { t.Resume(); } } // 結束執行 private void button2_Click(object sender, EventArgs e) { t.Suspend(); // 停止,掛起線程 this.Invoke(Fun1, "...停止"); } // 具體做事情的方法 public void Run() { //...... 處理一些事情,然后輸出日志 int i = 0; while (true) { i++; // this指Form2 //Invoke指: 在擁有控件的基礎窗口句柄的線程上,用指定的參數列表執行指定委托。 //Invoke的參數是一個委托類型,因此必須定義委托變量 this.Invoke(Fun1, i.ToString()); } } //在form初始化的時候,給委托變量賦值具體的方法 private void Form2_Load(object sender, EventArgs e) { //給委托變量初始化具體的執行方法 Fun1 = Print; } // 輸出日志的方法 public void Print(string msg) { // 新開辟的線程,不能直接調用這個方法。原因是控件只能由創建它的線程調用。 // 其他線程調用提示錯誤: 線程間操作無效: 從不是創建控件“richTextBox1”的線程訪問它。 this.richTextBox1.AppendText(msg + "\r\n"); this.richTextBox1.ScrollToCaret(); } } }
三、參考文章
1, C#多線程解決界面卡死問題的完美解決方案,BeginInvoke而不是委托delegate