2010-03-01 77 views
3

我有一些需要在應用程序啓動時填充的Janus網格控件。WinForms Control.BeginInvoke異步回調

我想加載這些網格在不同的線程上,以加快啓動時間和刷新這些網格所需的時間。每個網格都位於單獨的選項卡上。理想情況下,我想在每個網格上使用Control.BeginInvoke,並在網格加載完成時啓用標籤。

我知道Delegates在使用BeginInvoke時可以執行異步回調,所以我可以在異步回調中啓用這些選項卡,但是當使用Control.BeginInvoke時,這是不可能的。有沒有辦法使用Control.BeginInvoke或可能更好的解決方案做異步回調?

到目前爲止,我有:

public delegate void BindDelegate(IMyGrid grid); 

private IAsyncResult InvokeBind(IMyGrid grid) 
{ 
    return ((Control)grid).BeginInvoke(
    new BindDelegate(DoBind), new object[] { grid } 
); 
} 

private void DoBind(IMyGrid grid) 
{ 
    grid.Bind(); // Expensive operation 
} 

private void RefreshComplete() 
{ 
    IAsyncResult grid1Asynch = InvokeBind(grid1); 
    IAsyncResult grid2Asynch = InvokeBind(grid2); 
    IAsyncResult grid3Asynch = InvokeBind(grid2); 
    IAsyncResult grid4Asynch = InvokeBind(grid3); 
    IAsyncResult grid5Asynch = InvokeBind(grid4); 
    IAsyncResult grid6Asynch = InvokeBind(grid5); 
} 

現在我可以分拆單獨的線程,並繼續檢查,看看是否IAsynchResults已經完成,並取決於哪一個完成了,我可以重新啓用標籤控件的網格包含在內。有沒有更好的方法來做到這一點?

回答

1

任何對Control(包含所有標準和擴展WinForms控件的實例)的直接操作都必須在創建該控件的線程上完成。 Windows GUI不是線程安全的,實際上每個窗口都創建(並且大多數控件至少會創建一個)具有線程關聯性。

通常,其他線程使用Control.BeginInvoke在GUI線程上執行某些操作,以便可以正確讀取或設置屬性。

當然,您可以在線程池中啓動工作項以獲取稍後將填充網格的數據,但實際配置和網格填充(包括數據綁定)必須在GUI線程上完成。如果需要時間來獲取數據,這可能是一個好主意(但是由於數據源—的爭用,所以一起執行它們可能會比較慢),因爲您可以獲得GUI響應。

+0

也許它可以幫助在填充之前和之後使用'SuspendLayout()'和'ResumeLayout(false)',以便網格不會被繪製爲立即狀態。 – Oliver 2010-03-01 11:00:58