Yet another question about updating from background threads.
To get to the point: In the application, background threads need to update UI. I've considered using an in-between collection to buffer messages and have a timer to display them. At the moment we are trying a simplest approach.
Code attempt #1:
void foo(string status)
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate()
{
InsertStatusMessage(status);
}));
}
else
{
InsertStatusMessage(status);
}
}
This seems to have some flaws. Msdn states that InvokeRequired
also returns false
if the window handle hasn't been created yet (not available, in my opinion). So the code should be:
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");
}
}
The code above somehow also throws (for an unknown and not replicated reason). We use DevExpress and this is the unhandled exception message (no information nor any clue on what/where the error happened):
System.NullReferenceException: object reference not set to an instance of an object in DevExpress.Utils.Text.FontsCache.GetFontCacheByFont(Graphics graphics, Font font) in DevExpress.Utils.Text.TextUtils.GetFontAscentHeight(Graphics g, Font font) in DevExpress.XtraEditors.ViewInfo.BaseEditViewInfo.GetTextAscentHeight() in DevExpress.XtraEditors.ViewInfo.TextEditViewInfo.CalcTextBaseline(Graphics g) in DevExpress.XtraEditors.ViewInfo.BaseControlViewInfo.ReCalcViewInfo(Graphics g, MouseButtons buttons, Point mousePosition, Rectangle bounds) in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.UpdateCellEditViewInfo(GridCellInfo cell, Point mousePos, Boolean canFastRecalculate, Boolean calc) in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.CreateCellEditViewInfo(GridCellInfo cell, Boolean calc, Boolean allowCache) in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.RequestCellEditViewInfo(GridCellInfo cell) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRegularRowCell(GridViewDrawArgs e, GridCellInfo ci) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRegularRow(GridViewDrawArgs e, GridDataRowInfo ri) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRow(GridViewDrawArgs e, GridRowInfo ri) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawRows(GridViewDrawArgs e) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.DrawContents(GridViewDrawArgs e) in DevExpress.XtraGrid.Views.Grid.Drawing.GridPainter.Draw(ViewDrawArgs ee) in DevExpress.XtraGrid.Views.Base.BaseView.Draw(GraphicsCache e) in DevExpress.XtraGrid.GridControl.OnPaint(PaintEventArgs e)
in System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs) in System.Windows.Forms.Control.WmPaint(Message& m) in System.Windows.Forms.Control.WndProc(Message& m) in DevExpress.XtraEditors.Container.EditorContainer.WndProc(Message& m)
in DevExpress.XtraGrid.GridControl.WndProc(Message& m) in System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
in System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
I want to use Begin/End Invoke
instead of Invoke
because it requires less stuff (method delegates) and it is more readable.
What have I missed, how can I safely do thread invoking? I just want to add a message in a listbox. I really don't care if the calling thread will waits for a few milliseconds.