[英]Reliable/easy way to replace Windows.Forms control with a derived control?
[英]Windows Forms: Is there a way to wait for all pending Invokes to a Control to end?
我需要這樣做以解決僵局。 我的Windows窗體控件有對C ++ / CLI類的引用,該類包裝了C ++本機類。 本機類對C ++ / CLI類進行回調,該回調將它們映射到表單處理的事件。 從始終運行的線程中調用這些回調。
當我想處置控件時,我注銷所有事件,以使本機類不再能回調。 完成此操作后,我將處置C ++ / CLI包裝器,這反過來會破壞本機類。 在本機類析構函數中,我使用Windows事件通知線程結束,並無限期地等待線程結束。
但是,如果在處置開始時線程位於回調的中間,則可能在Control.Invoke
中將其停止,並隨后發生死鎖。 因此,標題問題。 這可能嗎? 如果是這樣,我可以這樣進行:
Invoke
均已完成,因此無法用Invoke
造成死鎖,並且由於未注冊事件而無法解雇它們) 我願意接受其他解決此問題的建議
選項1:在刪除事件處理程序之后但在析構函數之前,通過Application.DoEvents處理掛起的回調。 請注意,文檔說這可以處理Windows消息,並且沒有提及是否強制處理調用。
選項2:不阻止事件線程:通過BeginInvoke調用表單回調。 請注意,在C ++對象被銷毀后,您可能會得到事件,因此,請向事件處理程序中添加其他邏輯,以確保C ++對象未被銷毀。
FYI, BeginInvoke
和Invoke
都使用此功能。 BeginInvoke
將synchronous
設置為false。 請注意,我稍微修改了此方法以刪除不感興趣的部分:
private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
{
ThreadMethodEntry entry = new ThreadMethodEntry(caller, method, args, synchronous, executionContext);
lock (this.threadCallbackList)
{
if (threadCallbackMessage == 0)
threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
this.threadCallbackList.Enqueue(entry);
}
UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
// BeginInvoke just takes this branch instead of waiting for completion
if (!synchronous)
return entry;
if (!entry.IsCompleted)
this.WaitForWaitHandle(entry.AsyncWaitHandle);
if (entry.exception != null)
throw entry.exception;
return entry.retVal;
}
沒有可能響應表單關閉事件並等待線程完成。 有一個無法解決的線程競爭條件。 死鎖的可能性非常高,DoEvents可以打破死鎖,但是太丑陋了。
實現FormClosing事件,並告訴類停止運行其線程。 並取消關閉 。 線程應該在退出之前引發一個事件。 在事件處理程序中使用BeginInvoke()封送對主線程的調用。
現在,您可以保證所有調用均已完成,因為它們是有序的。 此外,您可以保證線程不再生成任何事件,因此不再有調用發生,並且取消訂閱事件是安全的(實際上不是必需的)。 設置一個標志,表明現在可以進行真正的關閉,並調用Close()來實際上關閉窗體。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.