簡體   English   中英

在打開表單之前使用Invoke時出現InvalidOperationException

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM