windows跨執行緒呼叫控制項的方法

2021-09-23 20:02:23 字數 2651 閱讀 5909

ui 的響應速度

,使得一切執行顯得更為快速。在

windows 

中進行多執行緒程式設計曾經是

c++ 

開發人員的專屬特權,但是現在,可以使用所有相容

microsoft .net 

的語言來編寫。

不過windows 窗體體系結構對執行緒使用制定了嚴格的規則。如果只是編寫單執行緒應用程式,則沒必要知道這些規則,這是因為單執行緒的**不可能違反這些規則。然而,一旦採用多執行緒,就需要理解 windows 窗體中最重要的一條執行緒規則:除了極少數的例外情況,否則都不要在它的建立執行緒以外的執行緒中使用控制項的任何成員。本規則的例外情況有文件說明,但這樣的情況非常少。這適用於其類派生自 system.windows.forms.control 的任何物件,其中幾乎包括 ui 中的所有元素。所有的 ui 元素(包括表單本身)都是從 control 類派生的物件。此外,這條規則的結果是乙個被包含的控制項(如,包含在乙個表單中的按鈕)必須與包含它控制項位處於同乙個執行緒中。也就是說,乙個視窗中的所有控制項屬於同乙個 ui 執行緒。實際中,大部分 windows 窗體應用程式最終都只有乙個執行緒,所有 ui 活動都發生在這個執行緒上。這個執行緒通常稱為 ui 執行緒。這意味著您不能呼叫使用者介面中任意控制項上的任何方法,除非在該方法的文件說明中指出可以呼叫。該規則的例外情況(總有文件記錄)非常少而且它們之間關係也不大。請注意,以下**是非法的:

private thread mythread;

private void form1_load(object sender, eventargs e)

private void runsonworkerthread()

如果您在 .net framework 1.0 版本中嘗試執行這段**,也許會僥倖執行成功,或者初看起來是如此。這就是多執行緒錯誤中的主要問題,即它們並不會立即顯現出來。甚至當出現了一些錯誤時,在第一次演示程式之前一切看起來也都很正常。但不要搞錯 — 我剛才顯示的這段**明顯違反了規則,並且可以預見,任何抱希望於「試執行時良好,應該就沒有問題」的人在即將到來的除錯期是會付出沉重代價的。

下面我們來看看有哪些方法可以解決這一問題。

private thread mythread;

private void form1_load(object sender, eventargs e)

private void runsonworkerthread()

private void setcontrolsprop()

二、直接用system.eventhandle(可帶引數)

private thread mythread;

private void form1_load(object sender, eventargs e)

private void runsonworkerthread()

//直接用system.eventhandler,沒有必要自定義委託

private void updateui(object o, system.eventargs e)

雖然第二個方法中的**解決了這個問題,但它相當繁瑣。如果輔助線程希望在結束時提供更多的反饋資訊,而不是簡單地給出「finished!」訊息,則 begininvoke 過於複雜的使用方法會令人生畏。為了傳達其他訊息,例如「正在處理」、「一切順利」等等,需要設法向 updateui 函式傳遞乙個引數。可能還需要新增乙個進度欄以提高反饋能力。這麼多次呼叫 begininvoke 可能導致輔助線程受該**支配。這樣不僅會造成不便,而且考慮到輔助線程與 ui 的協調性,這樣設計也不好。對這些進行分析之後,我們認為包裝函式可以解決這兩個問題。

private thread mythread;

private void form1_load(object sender, eventargs e)

private void runsonworkerthread()

}public void showprogress(string msg, int percentdone)

;begininvoke(new myprogresseventshandler(updateui), plist);

}private delegate void myprogresseventshandler(object sender, myprogressevents e);

private void updateui(object sender, myprogressevents e)

public class myprogressevents : eventargs

}showprogress 方法對將呼叫引向正確執行緒的工作進行封裝。這意味著輔助線程**不再擔心需要過多關注 ui 細節,而只要定期呼叫 showprogress 即可。

如果我提供乙個設計為可從任何執行緒呼叫的公共方法,則完全有可能某人會從 ui 執行緒呼叫這個方法。在這種情況下,沒必要呼叫 begininvoke,因為我已經處於正確的執行緒中。呼叫 invoke 完全是浪費時間和資源,不如直接呼叫適當的方法。為了避免這種情況,control 類將公開乙個稱為 invokerequired 的屬性。這是「只限 ui 執行緒」規則的另乙個例外。它可從任何執行緒讀取,如果呼叫執行緒是 ui 執行緒,則返回假,其他執行緒則返回真。這意味著我可以按以下方式修改包裝:

public void showprogress(string msg, int percentdone)

else

}

C 跨執行緒呼叫控制項

在c 應用程式開發中,我們經常需要把ui執行緒和工作執行緒分開程式設計,為了防止介面停止響應。同時,我們也需要在工作執行緒中去更新ui介面的控制項,在clr的執行緒安全中並不允許我們直接在工作執行緒操作ui介面。因此,介紹以下三種方式進行跨執行緒操作ui。private void button2 c...

C 跨執行緒呼叫控制項

在c 的應用程式開發中,我們經常要把ui執行緒和工作執行緒分開,防止介面停止響應。同時我們又需要在工作執行緒中更新ui介面上的控制項,下面介紹幾種常用的方法 閱讀目錄 執行緒間操作無效 第一種辦法 禁止編譯器對跨執行緒訪問做檢查 第二種辦法 使用delegate和invoke來從其他執行緒中呼叫控制...

跨執行緒呼叫控制項之MethodInvoker

這是一部分重要的 用vs2005通過。使用到兩個控制項,乙個按鈕button1,乙個標籤label1。private void button1 click object sender,eventargs e private void myname private void hello 那裡不正確,一...