Error when calling when the form is already closed

I am trying to display some information about the grid requested from sql server. Data collection can take about 10 seconds, so I do not want to block the user interface flow.

I currently have the code:

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, in addition, if the form in which it is located closes before the update is completed, it will fail with an error:

Invoke or BeginInvoke cannot be called in the control until a window handle is created.

I understand that the error will be caused by the fact that the form no longer exists, therefore, when the finally section tries to call the method in the user interface thread, it cannot.

Is there a better way to do all this? I suppose I can handle invoke errors, but it looks messy, and I think I probably skipped the simpler way.

+4
source share
3 answers

You can check if the form has been closed and not call if the form is closed. if (this.IsHandleCreated) should work. However, this can cause problems because the form may be closed between validation and calling BeginInvoke . The only "fully functional" solution is to wrap the entire call in try / catch.

+4
source

Try using InvokeRequired() before Invoke()

+1
source

Invoke uses special WinForms SynchronizationContext behind the scenes, which you can access using SynchronizationContext.Current anywhere in your application.

CORRECTION after deflecting Reflector : in fact, Invoke sends a direct sorting method through PostMessage, it is BackgroundWorker, which uses SynchronizationContext behind the scenes. Invoke will throw if it does not have a window handle.

Basically you need to save it in a variable before starting the stream, for example. while you are still in the user interface thread, and use the Post or Send method of the context in the thread code. This will cause the marker to be valid without window handles.

+1
source

All Articles