在UI上使用BackgroundWorker

2021-08-29 03:41:13 字數 3827 閱讀 8777

凡是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裡面的**,看一下就明白了:

public

partial

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...