C#中跨線程操做控件 --- InvokeRequired 屬性 與Invoke方法

在設計中爲了讓界面與邏輯分離,個人作法是使用事件,界面只要響應事件來處理界面的顯示就能夠了。而事件在邏輯處理中可能由不一樣的線程引起,這些事件的響應方法在修改頁面中的控件內容時便會引起一個異常。面試

這時就用到了Control.InvokeRequired屬性與Invoke方法。安全

獲取一個值,該值指示調用方在對控件進行方法調用時是否必須調用Invoke方法,由於調用方位於建立控件所在的線程之外的線程中。函數

若是控件的handle是在與調用線程不一樣的線程中建立的(說明您必須經過invoke方法對控件進行調用),則爲true,否者爲false。ui

Windows窗體中的控件被綁定到特定的線程,不具有線程安全性。所以,若是從另外一個線程調用控件的方法,那麼必須使用控件的一個invoke方法來將調用封送到適當的線程。該屬性可用於肯定是否必須調用invoke方法,當不知道什麼線程擁有控件時這頗有用。this

下面來講下具體的用法:.net

首先定義一個委託,與這個事件處理很熟的簽名同樣委託,固然直接使用該事件的委託也是能夠的,如:線程

private delegate void DoLog(string msg);

而後判斷這個屬性的值來決定是否要調用invoke函數:設計

if (this.InvokeRequired)
{
    DoLog doLog = new DoLog(Log);
	this.Invoke(doLog, new object[] { msg });
}

備註:這個函數就是事件處理函數,這樣就作到了窗體中控件的線程安全性。日誌

InvokeRequired當前線程不是建立控件的線程時爲truecode

好比你能夠本身開一個thread,或使用timer的事件來訪問窗體上的控件的時候,在線程中窗體的這個屬性就是true。

簡單的說,若是有兩個線程,thread A和thread B,而且有一個Control C,是在thread  A裏面new的。

那麼在thread A裏面運行的任何方法調用c.InvokeRequired都會返回false。

相反,若是在thread B裏面運行的任何方法調用c.InvokeRequired都會返回true。

是不是UI線程與結果無關。

一般Control所在的線程時UI線程,但也有例外。

若是InvokeRequired==true表示其它線程須要訪問空間,那麼調用invoke來轉給控件owner處理。

日誌輸出源碼

private delegate void DoLog(string msg);
private void Log(string msg){
	if (this.InvokeRequired){
		DoLog doLog = new DoLog(Log);
		this.Invoke(doLog, new object[] { msg });
	}else{
	    if (logReveal.Items.Count > 20) {
			logReveal.Items.RemoveAt(0);
		}
		msg = DateTime.Now.ToLocalTime().ToString() + " " + msg;
		logReveal.Items.Add(msg);
	}
}

 

天天一道面試題,持續更新@目錄

相關文章
相關標籤/搜索