关于从后台线程更新的另一个问题。
切入正题:在应用程序中,后台线程需要更新 UI。我考虑过使用中间集合来缓冲消息并有一个计时器来显示它们。目前我们正在尝试一种最简单的方法。
代码尝试#1:
void foo(string status)
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate()
{
InsertStatusMessage(status);
}));
}
else
{
InsertStatusMessage(status);
}
}
这似乎有一些缺陷。Msdn 指出,如果尚未创建窗口句柄(在我看来不可用),它InvokeRequired
也会返回。false
所以代码应该是:
void foo(string status)
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate()
{
InsertStatusMessage(status);
}));
// wait until status is set
EndInvoke(result);
}
else if(this.IsHandleCreated)
{
InsertStatusMessage(status);
}
else
{
_logger.Error("Could not update status");
}
}
上面的代码也以某种方式抛出(出于未知且未复制的原因)。我们使用 DevExpress,这是未处理的异常消息(没有任何信息,也没有关于错误发生的原因/位置的任何线索):
System.NullReferenceException:对象引用未设置为 DevExpress.Utils.Text.TextUtils.GetFontAscentHeight(Graphics g, Font font) 中的 DevExpress.Utils.Text.FontsCache.GetFontCacheByFont(Graphics graphics, Font font) 中的对象实例.XtraEditors.ViewInfo.BaseEditViewInfo.GetTextAscentHeight() 在 DevExpress.XtraEditors.ViewInfo.TextEditViewInfo.CalcTextBaseline(Graphics g) 在 DevExpress.XtraEditors.ViewInfo.BaseControlViewInfo.ReCalcViewInfo(Graphics g, MouseButtons buttons, Point mousePosition, Rectangle bounds) 在 DevExpress. DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.CreateCellEditViewInfo(GridCellInfo cell, Boolean calc,Boolean allowCache) 在 DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.RequestCellEditViewInfo(GridCellInfo cell) 在 DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRegularRowCell(GridViewDrawArgs e, GridCellInfo ci) 在 DevExpress.XtraGrid.Views.Grid .Drawing.GridPainter.DrawRegularRow(GridViewDrawArgs e, GridDataRowInfo ri) 在 DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRow(GridViewDrawArgs e, GridRowInfo ri) 在 DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRows(GridViewDrawArgs e) 在 DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawContents(GridViewDrawArgs e) 在 DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.Draw(ViewDrawArgs ee) 在 DevExpress.XtraGrid.Views.Base.BaseView.Draw (GraphicsCache e) 在 DevExpress.XtraGrid.GridControl 中。OnPaint(PaintEventArgs e)
在 System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs) 在 System.Windows.Forms.Control.WmPaint(Message& m) 在 System.Windows.Forms.Control.WndProc(Message& m) 在 DevExpress .XtraEditors.Container.EditorContainer.WndProc(Message& m)
在 DevExpress.XtraGrid.GridControl.WndProc(Message& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.Callback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
我想使用Begin/End Invoke
而不是Invoke
因为它需要更少的东西(方法委托)并且更具可读性。
我错过了什么,如何安全地进行线程调用?我只想在列表框中添加一条消息。我真的不在乎调用线程是否会等待几毫秒。