0

I already know that to update control, I can use Invoke Action

progressBar1.Invoke(new Action(() => { progressBar1.Maximum = 0; }));

But that only work with property of control which are single data. Now I have a thread that need to change the list view collection of list view items, clear it then update with new items, new texts and icon images. What is the different between them, an integer or a bool compare to a list, array or a collection of integer, bool or even component, control. Can I just simple add

string[] newItemText = {"item1", "item2", ...};
listView1.Invoke(new Action() => {
    i = 0;
    foreach(var item in listView1.Items)
    {
         item.Text = newItemText[i];
         i++; 
    }
}));

I may need a solution for my list view but if you have an answer, please explain clearly why and how it work, cause I need to learn thoroughly about it. Also you can notice me about the risk when trying that practice.

EDIT: The question is not about how to update control from other thread. IT about when and why need to do this and not to to that. Moreover, I need to know the different between update a single data and update the whole collection of data.

  • 1
    _"Can I just simple add"_ -- what happened when you tried that? How was that different from what you wanted? It's not clear at all what your actual question is. You seem to understand what you need to do. So...do that. If you have some specific trouble doing it, please explain what exactly that trouble is. Provide a good [mcve] showing exactly what you tried, along with a clear detailed explanation of what the code does and what you want it to do instead. – Peter Duniho Feb 10 '17 at 06:46
  • If you have that many UI work to do you need to rethink your design. Do cpu / IO work in the background and UI work on the UI thread as much as possible. Way better than complicating stuff. Take a look at async/await, it should help. See http://blog.stephencleary.com/2012/02/async-and-await.html and explorer from there. – Peter Bons Feb 10 '17 at 08:03
  • Possible duplicate of [How to update the GUI from another thread in C#?](http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c) – VMAtm Feb 10 '17 at 14:38
  • @Peter Duniho: The problem is I don't understand much about what is backgroundedly done. So it is no different or I need to concerned about any thing, that is my question. Will it run normally when I run debug but thrown exception when some user run it. – user3505230 Feb 10 '17 at 23:52
  • @Peter Bons: My mechanics is simple, fetch data to update my list view and fetch my listview (both old and new data) to update my winform (like load some pic or file), but I will consider your comment. – user3505230 Feb 12 '17 at 07:16

1 Answers1

1

There is no difference in updating a value or adding more elements to a list.

What internally happens is that the graphic resources being used to draw in Windows (it can also be applied to Android) it requires the usages of Pens, Brushes, and those type of objects.

Those objects belong to the context of the thread in which they have been instantiated originally. This typically happens in the main thread, but if you would create the graphical object, in this case the List, in a separate thread different that the main, that specific thread would be the "owner" thread of your control.

If you want to change something in the Control which requires refreshing the UI (requires the usages of Pens, Brushes, etc.) you have to do that from the same thread which "owns" your Control. That's why you need to use Invoke.

That's the main principle. If you update a scalar value as Integer, or if you add elements to a list, there is no difference. Both require the usage of graphical resources, so both require being called from the same thread that owns the Control.

Let me know if it is clear.

Edit. In any case your code looks a bit strange, because you are filling the List iterating from the own list. Wouldn't make more sense to do this?:

string[] newItemText = {"item1", "item2", ...};
listView1.Invoke(new Action() => {
   for(int i = 0; i < newItemText.length; i++)
   {
     listView1.add(newItemText[i]);
   }
});

without knowing the rest of the context, it sounds more logical to me.

Fernando
  • 396
  • 1
  • 5
  • Ok, if we change UI then it use the UI thread which is the original thread of the UI. But why I am not change anything, just assign or reach specific value and it thrown an exception. Like this ListViewItem item = listView1.Items[i]; – user3505230 Feb 11 '17 at 00:08
  • in your example you are assigning to the text property: item.Text = newItemText[i]; And that is changing the UI. In any case your example looks a bit weird to me. I will edit my post to put what I think you should do. – Fernando Feb 11 '17 at 15:00
  • Well,your code only work if it modified the list view one time,what if each time I click the button, the list view need to update it outlook. So the problem is I don't know how and why to do it. Because in an other thread, I need to read that list view text to process. So my main question and my comment question are different. One thread is fetch data from somewhere to update my list view, one other thread fetch text from list view for other process, which one need invoke cause both throw invalid operation despite fact that I only read data from my list view in the latter. – user3505230 Feb 12 '17 at 07:12
  • Well. Don't read data from the ListView. Just use ListView as output, I would suggest to use 1 input and 2 outputs being the ListView 1 output. I onn't think there would be a problem in reading the data from the Listview in a different thread, but it is more cumbersome in my opinion. Use one thread to populate the data in thread A. Access the data (use locks to protect concurrency in the shared memory of both threads) from thread B or C to get the information to show in the list. – Fernando Feb 12 '17 at 10:15
  • Maybe you get lost in my telling. The two thread is not parallel so I don't need lock. I mean I fetch the list of file of a directory into list view. Then after user choose from list view, I fetch the chosen item from list view which contain file name to load it into viewer. Load it into 2 output is quite annoyance to me cause we need to chose exactly from the list view. – user3505230 Feb 13 '17 at 09:01
  • But your answer is the correct answer to me, especially explain why with UI thread and original thread. I only need to add that in my case, the second thread that load data from the list view also need the Invoke. It need because it READ data from list view with ASSIGN code ListViewItem item = listView1.Items[i]; So the right way is ListViewItem item = null; listView1.Invoke(new Action(() => { item = listView1.Items[i]; })); – user3505230 Feb 13 '17 at 09:06
  • CONCLUSION: If you don't run with the Invoke code for ASSIGN, even if you don't change the data of list view, you will get surely invalid operation exception. – user3505230 Feb 13 '17 at 09:09