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 have created a collection of 'ConccClass' in my view model and binded it with datagrid on xaml in view.
Question When I add an item on a background thread simply without any dispacther it does not reflect in datagrid. means no item added. Todo this I have to add the item in Dispatcher. BeginInvoke. Which make sense to me.
But to update the Name of any Item I dont need 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 such behavior?
The true difference is rather straightforward: ObservableCollection<T> implements INotifyCollectionChanged which provides notification when the collection is changed (you guessed ^^) It allows the binding engine to update the UI when the ObservableCollection is updated. However, BindingList<T> implements IBindingList .
ObservableCollection is the recommended collection to use for ListViews, but it isn't thread safe.
An ObservableCollection is a dynamic collection of objects of a given type. Objects can be added, removed or be updated with an automatic notification of actions. When an object is added to or removed from an observable collection, the UI is automatically updated.
This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes. WPF provides the ObservableCollection<T> class, which is a built-in implementation of a data collection that implements the INotifyCollectionChanged interface.
The following is a short explanation:
You probably have an UI element binded to the observable collection. When you add an element to the observable collection, the UI updates to reflect changes. However, the only thread allowed to make changes to UI is the main thread.
So when you add an item to the observable collection using a background thread, the UI tries to update using the background thread, which is not allowed to make changes to UI, and an exception is thrown.
I am pretty 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 are making the update using the main thread, and for that reason it works.
The update to properties work, because you are just raising an event. The framework should listen for that event and make sure to dispatch it to the main thread automatically.
A simple way to avoid these exceptions is to use the BindableCollection from Caliburn.Micro. This is a ObservableCollection that will automatically dispatch the CollectionChanged events to the Main Thread.
Only Use the BindableCollection in your ViewModels because the CollectionChanged events will be on the Main Thread and for performance reasons you would like to do the most of the coding on a background Thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With