[英]InvalidOperationException when using Invoke before the form was opened
例外是這樣的:
System.InvalidOperationException:在創建窗口句柄之前,無法在控件上調用Invoke或BeginInvoke。
首先,我將解釋我的應用程序中的關系。 有一個名為MainForm的表單和另一個名為AssetsForm的表單。 MainForm正在MainForm的constrcutor中創建AssetsForm的一個實例,但它還沒有AssetsForm.Show()。
有一個名為AssetsSource的類,它實現IObservable並將數據發送到實現IObserver的AssetsForm。 當AssetsForm接收要顯示的數據時,它會創建一個BackgroundWorker來處理數據並更新TreeView。
我已經實現了以下錯誤的代碼來處理來自BackgroundWorker的UI更新:
private void Invoke(Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
control.Invoke(action);
}
}
這是錯的,因為我不應該使用Invoke(action)來編寫動作(); 但我稍后會提到這一點。 無論如何,從Invoke(action)代碼行拋出了InvalidOperationException。 我可以推斷InvokeRequired評估為FALSE,盡管我從BackgroundWorker更新了TreeView!
在MSDN中,它是關於Control.Invoke寫的:
Invoke方法搜索控件的父鏈,直到找到具有窗口句柄的控件或窗體(如果當前控件的基礎窗口句柄尚不存在)。 如果找不到合適的句柄,Invoke方法將拋出異常。
什么是父鏈,什么是窗口句柄? 創建窗口句柄時? 我想這一切都與AssetsForm關閉的事實有關。
當我刪除該行並僅使用action(); 應該是,程序不會崩潰。
在AssetsSource向AssetsForm發送更新之前打開 AssetsForm時,通過調試我可以看到InvokeRequired被評估為TRUE並且TreeView的BeginInvoke更新自身。
總結一下,我不明白為什么當AssetsForm關閉時,InvokeRequired為false,並且允許UI更新(TreeView)來自未創建TreeView的線程。
只要窗口未顯示,Winforms就不需要堅持使用UI線程機制。 因此InvokeRequired
返回false。
如果調用Show()
,則會打開窗口,並且所有UI活動都需要通過事件循環運行,因此需要通過UI線程運行。
背景 :僅通過主線程處理UI活動的限制是由於只有一個(窗口)事件循環正在處理所有與UI相關的活動。 為了確保所有活動都以正確的順序運行,所有操作都需要通過一個線程運行(至少在winforms中)。 只要未顯示表單,就不會觸發任何事件,因此不需要強制所有操作都通過主線程運行。
編輯:添加一些背景說明。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.