Accessing a DataGridView control from a thread that it wasn't created in???

This is the exception I'm getting:

"Cross-thread operation not valid: Control 'dgvLogResults' accessed from a thread other than the thread it was created on."

I'm trying to update a datagridview with new data that has been detected in a thread that is running and polling. But I can't seem to get this to work do I have to reference the original thread somehow then access the control



Answer this question

Accessing a DataGridView control from a thread that it wasn't created in???

  • ylmz

    I'm really horrible with delegates still getting my head around them.  So if I want access the DataGridView I write

    public void myDelegate();

    // Do I need to invoke to use this control

    If( myDataGridView.InvokeRequired )

    {

    // Yes so call a delegate which points to a method in my class

    myDataGridView.BeginInvoke( new myDelegate( AutoUpdateDGV ) );

    }

    public void AutoUpdateDGV()

    {

    // Update this control

    }

    I can see how this works... and this can all happen within my one class... ya I think I have it... Does this look okay   Do I need to make a delegate like I did above   You seem to be call a straight method or recursively calling if that second call to searchComplete isn't supposed to a lower case. 


  • Zacharia

    Use BeginInvoke on the form that contains the object. Depending on how you have it set up you might also want to use InvokeRequired.

    I tend to use things like the following:

    private void SearchComplete() {

    if (this.InvokeRequired) {

    BeginInvoke(searchComplete);

    }

    else {

    this.Cursor = Cursors.Default;

    }

    }


  • Ceyhun PAK

    Sorry, "searchComplete" is an instance of a delegate that referrs to "SearchComplete". The only change I would make would be to use a single method (with a sorta-recursive call using BeginInvoke).

    So yours would be:

    public void myDelegate();

    public void AutoUpdateDGV(){

    if (myDataGridView.InvokeRequired()){

    myDataGridView.BeginInvoke(new myDelegate(AutoUpdateDGV));

    }

    else{

    // update the data grid here

    }

    }

    This allows all the code that is doing the update to be done in the same method.

    I don't know if the above is really good practive, but it does work. I think the better practice is to call BeginInvoke from the method in the seperate thread. This requires that you design threads to know if they are updating the GUI and use the appropriate method to do so. One problem with the above method is that it does not allow the calling thread to distinguish between BeginInvoke and Invoke.


  • Coach David

    hmmm I'm sorry I don't think I understand I put some of my code below the comments make it a quick read Only three methods...

    // START THREAD

    private void RunAutoUpdateDataLogViewerThread()

    {

    // Instantiate data log viewer auto update thread

    tcpViewer = new Thread(new ThreadStart(AutoUpdateDataLogViewer));

    // Call thread start method to place thread in the running state

    tcpViewer.Start();

    }

    // RUNNING THREAD

    private void AutoUpdateDataLogViewer()

    {

    while (datalogScreen.Visible)

    {

    // Check IsDone reading transmitted data flag

    if (tcpManager.CheckTCPIsDoneReading())

    {

    // Clear IsDone reading transmitted data flag

    tcpManager.ClearTCPIsDoneReading();

    // Update DataGridView logged results

    UpdateDataGridView();

    }

    else

    {

    // Put thread to sleep for five seconds

    Thread.Sleep(5000);

    }

    }

    }

    // UPDATE DATAGRIDVIEW so this is the function I should use BeginInvoke() by putting it above by 7 or 8 lines like

    BeginInvoke(UpdateDataGridView()); where I should make up a delegate for UpdateDataGridView()

    // Update DataGridView logged results

    public void UpdateDataGridView()

    {

    // Build DataSet

    DataSet dbset = dbutes.BuildDataSet(BuildViewLoggingSQL(), "tblRdrLog");

    // Fill DataGridView with logged data

    FillDataGridView(dbset, this.dgvLogResults);

    }


  • MrBobo

    // UPDATE DATAGRIDVIEW so this is the function I should use BeginInvoke() by putting it above by 7 or 8 lines like

    BeginInvoke(UpdateDataGridView()); where I should make up a delegate for UpdateDataGridView()

    Correct, if you replace the direct call with a BeginInvoke you should be good.


  • Accessing a DataGridView control from a thread that it wasn't created in???