美好的一天!在Dispose中等待Backgroundworker()
我有自定義popupcontainer control
- comboBox在那裏你可以把其他控件,他們會出現彈出。在我的情況下,它包含datagrid
。我想讓它工作得更快 - 只有當用戶決定彈出我的控件時,我才需要該數據網格。我決定將datagrid創建移動到其他線程,並使用Backgroundworker
,因爲它非常適合用戶界面,我不想混亂Control.Invoke。這裏是我的簡化代碼:
protected override void OnCreateControl()
{
base.OnCreateControl();
CreateContainer();
}
protected virtual void CreateContainer()
{
_worker = new BackgroundWorker();
_worker.DoWork += DoActionsOnAsyncWork;
_worker.RunWorkerCompleted += AsyncWorker_RunWorkerCompleted;
_worker.RunWorkerAsync(this);
}
protected void DoActionsOnAsyncWork(object sender, DoWorkEventArgs e)
{
var _grid = ///Create and initialize local grid here
e.Result = _grid; // Throw it to RunWorkerCompleted event
}
private void AsyncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null && !IsDisposed && !IsDisposing)
{
if (!_closing)
{
this.Grid = e.Result as MyGrid;
AttachEventHandlersToGrid();
} else
(e.Result as MyGrid).Dispose(); // Get rid of grid
}
// Get rid of worker
_worker.DoWork -= DoActionsOnAsyncWork;
_worker.RunWorkerCompleted -= AsyncWorker_RunWorkerCompleted;
_worker.Dispose();
_worker = null;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
WaitForBackgroundWorker();
// Dispose other stuff
...
}
base.Dispose(disposing);
}
protected void WaitForBackgroundWorker()
{
if (_worker == null ||
!_worker.IsBusy)
return;
_closing = true;
while (_worker != null && _worker.IsBusy)
Application.DoEvents(); // Hack throw worker.RunWorkerCompleted on top of msg queue
}
現在,我需要等待_worker
爲了妥善處理我的控制(形式爲更大範圍內)。此外_worker
創建grid
也是需要處理的。我的問題是 - 如何在沒有Application.DoEvents()的情況下等待backgroundworker
。因爲有時(通常在遠程桌面 - 也許是其他一些繪畫算法?),它會導致整個應用程序掛起。調用堆棧:
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x1f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x23 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x1c bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) + 0x96 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) + 0x34b bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) + 0x50 bytes
System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) + 0x56 bytes
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization, object[] args) + 0x66 bytes
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization, object key, object[] args) + 0x110 bytes
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(object key, object[] args) + 0xe bytes
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg, System.IntPtr wParam, System.IntPtr lParam) + 0x76 bytes
System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd, int msg, System.IntPtr wParam, System.IntPtr lParam) + 0x2c6 bytes
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x357 bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x33d bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x5f bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.DoEvents() + 0x18 bytes
MyControl.WaitForBackgroundWorker() Line 874 + 0x1b bytes
... // Many recursive disposes
Form.Dispose()
你不能等待,這將導致死鎖之間。檢查這個答案:http://stackoverflow.com/a/1732361/17034 –
@Hans Passant然後,我感到困惑。是否真的沒有辦法等待'backgroundworker'完成它的兩個事件 - DoWork和RunWorkerCompleted?我有'QueryPopUp'事件,我使用Application.DoEvents()沒有循環,它的工作(幸運?)。我在'backgroundworker.DoWork'事件中通過Thread.Sleep()測試了它。還有一個詞可能會調用Application.DoEvents()始終強制backgroundworker.RunWorkerCompleted完成? – nikita
RunWorkerCompleted是這個問題,它只能在UI線程正在泵送消息時運行。是的,DoEvents是避免僵局的一種手段。龍住在那裏。 –