0

We've made an Application with a MainWindow called MV.

When main starts it launches our StartProgram method as a BackgroundWorker and the Application.Run(MW);

MainWindow MW = new MainWindow();
BackgroundWorker.DoWork += (obj, e) => StartProgram(MW);
BackgroundWorker.RunWorkerAsync();
Application.Run(MW);

In StartProgram we create instances of Patient, which we want to show in our listView1. We do this by calling this method, which is in MW:

public void SetListSource(Patient p)
{
    ListViewItem item = new ListViewItem("woohoo");
    item.SubItems.Add("a");
    listView1.Items.Add(item);
}

StartProgram stalls when it reaches listView1.Items.Add(item);

Our guess is, that it waits for MW (MainWindow), but we can't figure out how to fix it. We have a button in MW, that does somethis similar, except it only sends "1" and "a" to the listView1.

private void Sort_Button_Click(object sender, EventArgs e)
{
    ListViewItem item = new ListViewItem("1");
    item.SubItems.Add("a");
    listView1.Items.Add(item);
}

Does anybody know how to make SetListSource(...) work as Sort_Button_Click(...)?

EDIT Solved with Invoke

user3265569
  • 175
  • 2
  • 11

2 Answers2

1

You can't modify your GUI directly from another thread. You need to use a delegate and invoke your control. In your thread you have to do:

CONTROL.Invoke(new Action(() =>
{
  CONTROL.Items.Add(item);
}
));

Source:

BackgroundWorker multithread access to form

Community
  • 1
  • 1
Btc Sources
  • 1,912
  • 2
  • 30
  • 58
0

You can use Invoke, but that's probably unnecessary. You can use BackgroundWorker.RunWorkerCompleted event instead:

BackgroundWorker.DoWork += 
  (s, e) => 
  {
    e.Result = DoAllTheComplicatedWork();
  }
BackgroundWorker.RunWorkerCompleted +=
  (s, e) =>
  {
    // Back on the UI thread, we can do whatever we want
    listView1.Items.Add(((SomeDTO)e.Result).Patient);
  }
BackgroundWorker.RunWorkerAsync();

Or, you can do the whole thing using await:

MW.Load += async (s, e)
  {
    var result = await Task.Run(() => SomeCPUWork());
    listView1.Items.Add(((SomeDTO)e.Result).Patient);
  }

The key point is, you really want a separation between the UI and whatever you need to do in background. I definitely wouldn't pass a form (or any other control) to any method that's supposed to be executed on a different thread.

Luaan
  • 62,244
  • 7
  • 97
  • 116