The observed collection change is not updated in the user interface, but the normal property is notified

I have two classes

public class ConccClass<T> : ObservableCollection<T> { } 

and

 public class TestTherad: INotifyPropertyChanged { private string name; public string Name { get { return name; } set { if (value != name) { name = value; RaisePropertyChanged("Name"); } } } //// the notification implemented fully here } 

Now I created the "ConccClass" collection in my view model and linked it to the xaml datagrid in the view.

Question When I add an element to the background stream simply without any indication, it is not reflected in the datagrid. means the item has not been added. That's where I should add an item to the dispatcher. BeginInvoke. Which makes sense to me.

But to update the name of any element, I do not need a dispatcher.

 Task.Factory.StartNew(() => { while (true) { Thread.Sleep(100); { this.Dispatcher.Invoke(() => this.Coll.Add(new TestTherad())); // **Works well** //this.Coll.Add(new TestTherad()); // **does not work at all.** this.Coll[0].Name = r.Next().ToString(); // ** without dispatcher works well.** } } }); 

Why is this behavior?

+5
source share
4 answers

The following is a brief explanation:

You probably have a user interface element associated with the observed collection. When you add an item to the monitored collection, the user interface is updated to reflect the changes. However, the only thread allowed to make changes to the user interface is the main thread.

Therefore, when you add an item to the observed collection using a background thread, the user interface tries to update the background thread, which does not have the right to make changes to the user interface, and an exception is thrown.

I am sure that this line should throw an exception: //this.Coll.Add (new TestTherad ()) ;. Try debugging inside the task block.

When you use the dispatcher, you do the update using the main thread, and for this reason it works.

Updating properties works because you are simply raising an event. The structure should listen to this event and be sure to send it to the main thread automatically.

+5
source

An easy way to avoid these exceptions is to use the BindableCollection from Caliburn.Micro. This is an ObservableCollection that automatically dispatches CollectionChanged events to the main thread.

Use only BindableCollection in your ViewModels, because CollectionChanged events will be in the main thread and for performance reasons you would like to use most of the code in the background thread.

+3
source

Most of the previous comments have already answered this, however this should be summarized. Prior to .NET 4.5, you could only call updates in the ObservablCollection in the user interface thread. This is achieved by calling Dispatcher.Invoke. Calling the updated name of the object does not affect collection events, etc., but only on the object. However, ideally, updating the properties of objects should also be performed only in the user interface thread, but depending on how the property is bound, you can sometimes leave with updating these properties from a thread other than ui. As already mentioned, this will depend on which version of .Net is used.

+1
source

In Github you will find a small helper class called AsyncObservableCollection: Github This is a very thin shell around the OberserableCollection. He takes care of all the threading problems you mention. You create a collection from your ui thread and then use the collection from any stream you want.

0
source

Source: https://habr.com/ru/post/1206150/


All Articles