2010-03-01 89 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