public void RefreshData()
{
// this is called on UI thread
List<ds> dataSource;
GetDsDelegate caller = GetDs;
caller.BeginInvoke(out dataSource, RefreshCallback, null);
}
private void RefreshCallback(IAsyncResult ar)
{
// this is called on worker thread
try
{
var result = (AsyncResult)ar;
var caller = (GetDsDelegate)result.AsyncDelegate;
List<ds> dataSource;
var success = caller.EndInvoke(out dataSource, ar);
if (success)
{
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
}
}
catch
{
// NOTE: It's possible for this form to close after RefreshData is called
// but before GetDs returns thus the SetGridDataSource method no longer exists.
// Not catching this error causes the entire application to terminate.
}
private void SetGridDataSource(List<ds> dataSource)
{
// this is called on UI thread
dataGrid.DataSource = dataSource;
}
RefreshData,RefreshCallback和SetGridDataSource都是windows Form類的所有方法。調用RefreshData使用GetDsDelegate委託調用外部方法GetDs。當GetDs完成時,它調用RefreshCallback(現在在一個單獨的線程上)。最後,調用SetGridDataSource來完成更新。如何處理丟失的調用方法
所有這些工作正常,除非GetDs被延遲並且窗體關閉。然後,當GetDs完成並調用RefreshCallback時,SetGridDataSource不再存在。
除了顯示的try/catch塊之外,還有更好的方法來處理這種情況嗎?我寧願防止錯誤,而不是忽略它。有更好的模式可供使用嗎?
編輯
我看着那個錯誤,很明顯改變if (success)
到if (success && IsHandleCreated)
,以防止它,但它仍然好像我做錯了什麼,或者至少尷尬。我也可以用Invoke替換第二個BeginInvoke,所以EndInvoke是不必要的。我喜歡將邏輯從表單移開的想法,但我不明白結果會如何改變。我認爲BackgroundWorker也會有同樣的問題;作爲回調不再可訪問。我想可以提出一個事件的結果,但這似乎有點抽象。你能否詳細說明一下或者提供一個例子。
這是一個無法解決的競爭條件,你不能允許表單關閉,直到所有工作線程完成運行。使用BackgroundWorker可以更輕鬆地完成此任務。 – 2012-02-03 02:44:48