1

Is there a way to run code in UI thread while calling it outside of it? I know that it basically requires the use of control.Invoke or control.BeginInvoke. My problem is that i don't have access to UI elements to use those methods.

My situation is like this:

  1. UI - DataGridView with DataTable set as it's DataSource
  2. thread (BackgroundWorker) written outside of MainForm UI, that updates (adds rows) DataTable mentioned above

I've had problems with my app, so i've written a simple app with just the elements mentioned above, to check how it works (or rather why it doesn't) and I found that:

  1. when I update DataTable in my BackgroundWorker thread, DataGridview can't see this (probably all the events are fired from other thread), even calling DGV.Refresh() doesn't work (it updates DGV, but sometimes DGV gets broken and shows nothing or just 1 row), only forcing DGV refreshing with resizing, scrolling etc. forces DGV to show data from DataTable
  2. when I am able to run Invoke, everything works fine, nothing more to say

but this is just a simple app, where I have everything in a single file. what can i do with much greater app where my "other thread" can't see UI code? do I have to pass a single control as a parameter somehow, just to get access to that thread? or is there maybe some other, much better looking solution?

Soul Reaver
  • 2,012
  • 3
  • 37
  • 52
  • Separate the datasource and control from the UI and the BackgroundWorker. That way either of the 2 can access a common control. Look into IoC for ideas. You could use async/await as well, but from the sound of it, you don't have access to the UI code at all? So you are manipulating a 3rd party program? – user3036342 Dec 18 '14 at 09:07
  • 1
    How about using the `ReportProgress` method and the `ProgressChanged` event to actually update your UI? They are made for exactly that purpose. See http://msdn.microsoft.com/en-us/library/System.ComponentModel.BackgroundWorker%28v=vs.110%29.aspx for an example. – Dirk Vollmar Dec 18 '14 at 09:08
  • This can help you : [WinForms multi-threaded databinding scenario, best practice?](http://stackoverflow.com/questions/602735/winforms-multi-threaded-databinding-scenario-best-practice) – Larry Dec 18 '14 at 09:11
  • I guess you are creating a new thread for update data from UI thread. You should be able to get the callback then do the UI update using control.BeginInvoke. And if you need better binding, use BindingSource. – Eric Dec 18 '14 at 09:18

2 Answers2

7

you can use Application.OpenForms by this:

    public void DoSomething(string s)
    {
        var form = System.Windows.Forms.Application.OpenForms[0];
        if (form.InvokeRequired)
        {
            Action<string> m = DoSomething;
            form.Invoke(m, s);
            return;
        }

        //do something
    }
Kent Liu
  • 86
  • 3
  • work like charm ^_^ of course, maybe there are better solutions, but this one is all that I need for now, thanks – Soul Reaver Dec 18 '14 at 09:30
1

You could always use Application.OpenForms[0] to obtain a reference to the main form and thus have something to call Invoke on.

Also I'd say that your approach is not so smart. I'd create a new DataTable in the background worker and return it as the background worker's result.

Then, when the worker is finished (the RunWorkerCompleted event is called in the context of the UI thread), I'd merge the result records into the bound data table. This provides a clear separation of code that updates the UI and code that might even run headless.

Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139