I am trying to display some information on a grid queried from a sql server. The data gathering can take about 10 seconds so I don't want to lock the UI thread.
I currently have code like:
ThreadPool.QueueUserWorkItem(DataUpdateThread, new UpdateParams(year));
private struct UpdateParams
{
internal string year;
internal UpdateParams(string year)
{
this.year = year;
}
}
private void DataUpdateThread(object state)
{
DataTable dTable = new DataTable();
try
{
this.Invoke((MethodInvoker)delegate
{
//stop data editing on the grid
//scrolling marquee for user
marquee.Visible = true;
marquee.Enabled = true;
grdMain.Visible = false;
grdMain.DataSource = null;
});
UpdateParams parameters = (UpdateParams)state;
dTable = GetData(parameters.year);
}
catch (Exception ex)
{
this.Invoke((MethodInvoker)delegate
{
//log error + end user message
});
}
finally
{
this.Invoke((MethodInvoker)delegate
{
grdMain.DataSource = dTable;
grdMainLevel1.RefreshData();
marquee.Visible = false;
marquee.Enabled = false;
grdMain.Visible = true;
});
}
}
This works most of the time apart from if the form it is on is closed before the update completes it will crash with the error:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
I understand the error will be because the form no longer exists so when the finally section tries to invoke the method on the UI thread it can't.
Is there a better way to do this whole thing? I guess I can handle the invoke errors but it looks messy and I think I have probably missed a simpler way.