凡是winform的應用程式,如果他執行了乙個的非常冗長的處理操作(比如檔案查詢),它在執行時會鎖定使用者介面,雖然主活動視窗 一直在執行,但使用者無法與程式互動,無法移動窗體或改變窗體大小,所以使用者感覺很不爽。如何做才能使得這個程式有響應。答案就是在後台執行緒中執行這個操 作。
在這裡已經有了多種方法來做這個事情:
(一)委託非同步呼叫
將具體耗時的操作作為乙個委託,並用begininvoke來非同步執行這個委託(invoke是同步呼叫),並且可以為這個操作傳入引數並且通過endinvoke方法獲得返回返回值。
(二)使用threadpool
新建.net framework中自帶的waitcallback委託,然後放到執行緒池中執行threadpool.queueuserworkitem( callback ); 根據waitcallback委託的定義,可以傳入乙個object型別的引數。
但是不能精確的控制線程池中的執行緒。
(三)使用thread
和threadpool相比,使用thread的開銷會比較大。但是它有它的優勢,使用 thread 類可以顯式管理執行緒。只要有可能,就應該使用 threadpool 類來建立執行緒。然而,在一些情況下,您還是需要建立並管理您自己的執行緒,而不是使用 threadpool 類。在.net 2.0 中,提供了乙個新的委託 parameterizedthreadstart 支援啟動乙個執行緒並傳入引數,這是對原來的threadstart委託的改進。
說了這麼多還沒有說到今天的主角backgroundworker,他也是乙個在2.0中新增的類,可以用於啟動後台執行緒,並在後台計算結束後呼叫主線程 的方法.可以看出同樣的功能使用委託的非同步呼叫也可以實現,只是使用backgroundworker的話會更加的簡便快捷,可以節省開發時間,並把你從 建立自己的委託以及對它們的呼叫中解救出來。真是這樣的嗎看看下面這個例子。其實我也是從101samples中看到的例子。
先看看backgroundworker中的主要概念。
第一:主要的事件及引數。
dowork——當執行backgroundworker.runworkerasync方法時會觸發該事件,並且傳遞doworkeventargs引數;
progresschanged——操作處理中獲得的處理狀態變化,通過backgroundworker.reportprogress(int)方法 觸發該事件,並且傳遞progresschangedeventargs,其中包含了處理的百分比;
runworkercompleted ——非同步操作完成後會觸發該事件,當然如果需要在操作過程中結束可以執行backgroundworker.cancelasync方法要求非同步呼叫中 止,並且在非同步委託操作中檢測backgroundworker.cancellationpending屬性如果為true的話,跳出非同步呼叫,同時將 doworkeventargs.cancel屬性設為true,這樣當退出非同步呼叫的時候,可以讓處理runworkercompleted事件的函式 知道是正常退出還是中途退出。
第二:主要的方法。
backgroundworker.runworkerasync——
「起動」非同步呼叫的方法有兩次過載runworkerasync(),runworkerasync(object argument),第二個過載提供了乙個引數,可以供非同步呼叫使用。(如果有多個引數要傳遞怎麼辦,使用乙個類來傳遞他們吧)。呼叫該方法後會觸發 dowork事件,並且為處理dowork事件的函式doworkeventarg事件引數,其中包含了runworkerasync傳遞的引數。在相應 dowork的處理函式中就可以做具體的複雜操作。
backgroundworker.reportprogress——
有時候需要在乙個冗長的操作中向使用者不斷反饋進度,這樣的話就可以呼叫的reportprogress(int percent),在呼叫 reportprogress 方法時,觸發progresschanged事件。提供乙個在 0 到 100 之間的整數,它表示後台活動已完成的百分比。你也可能提供任何物件作為第二個引數,允許你 給事件處理程式傳遞狀態資訊。作為傳遞到此過程的 progresschangedeventargs 引數屬性,百分比和你自己的物件(如果提供的話)均要被傳遞到 progresschanged 事件處理程式。這些屬性被分別命名為 progresspercentage 和 userstate,並且你的事件處理程式可以以任何需要的方式使用它們。(注意:只有在 backgroundworker.workerreportsprogress屬性被設定為true該方法才可用)。
backgroundworker.cancelasync——
但需要退出非同步呼叫的時候,就呼叫的這個方法。但是樣還不夠,因為它僅僅是將backgroudworker.cancellationpending屬 性設定為true。你需要在具體的非同步呼叫處理的時候,不斷檢查backgroudworker.cancellationpending是否為 true,如果是真的話就退出。(注意:只有在backgroundworker.workersupportscancellation屬性被設定為 true該方法才可用)。
貼出一段101samples裡面的**,看一下就明白了:
publicpartial
class
mainform : form
private
intgetnextprimeasync(
intstart, backgroundworker worker, doworkeventargs e)
else
}return
start;
}void
backgroundcalculator_runworkercompleted(
object
sender, runworkercompletedeventargs e)
else
if(e.error
!=null
)else
calcprogress.value =0
;}void
backgroundcalculator_progresschanged(
object
sender, progresschangedeventargs e)
void
backgroundcalculator_dowork(
object
sender, doworkeventargs e)
private
void
nextprimeasyncbutton_click(
object
sender, eventargs e)
else
}private
void
cancelbutton_click(
object
sender, eventargs e)}//
update the status label
private
void
updatestatus(
string
status)
//indicate progress using progress bar
private
void
updateprogress(
intpercentcomplete)
} backgroundworker建立自己的委託並呼叫這個窗體的 invoke 方法來執行它,backgroundworker 元件以一種優雅的方式來處理這個執行緒轉換。backgroundworker 元件允許你從後台執行緒中呼叫它的 reportprogress 方法,該方法觸發其 progresschanged 事件處理例程返回到窗體的執行緒中。你不必使用 delegate/invoke 方法自己處理這個執行緒轉換,而是呼叫 reportprogress,其餘的事情交給元件來做。
在UI上使用BackgroundWorker
凡是winform的應用程式,如果他執行了乙個的非常冗長的處理操作 比如檔案查詢 它在執行時會鎖定使用者介面,雖然主活動視窗一直在執行,但使用者無法與程式互動,無法移動窗體或改變窗體大小,所以使用者感覺很不爽。如何做才能使得這個程式有響應。答案就是在後台執行緒中執行這個操作。在這裡已經有了多種方法來...
模型在UI上顯示
接到的任務需求是在將3d模型的內容在ui上顯示 梳理了目前有3個種方式,當然沒有好壞之分,只有合適與否。在開源專案中sometips的scenes資料夾中,加入3duiwayno1 3的場景,看到以上的實現方式。camer是skybox直接與ui混合。如果在放在ui節點下,因為在同一層級下,通過控制...
在非UI執行緒使用Handler
handler物件所繫結的執行緒並不取決於該handler物件由哪個執行緒構建,而是取決於該handler物件所繫結的looper屬於哪個執行緒。looper就像乙個訊息佇列 messagequeue 的管家,乙個訊息佇列只有乙個管家,並且管理者整個訊息佇列,而乙個訊息佇列內可以容納多個訊息 mes...