I am having a class
named Employee
. I need to update only the property Status
from thread other than current dispatcher thread:
class Employee
{
public string Name { get; set; }
public string Status { get; set; }
}
Viewmodel (ViewModelBase
inherited from inotifypropertychanged
interface):
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class DisplayViewModel : ViewModelBase {
public static event EventHandler OnStatusChanged;
ObservableCollection<Employee> _dailyEmployees;
public ObservableCollection<Employee> DailyEmployees
{
get { return _dailyEmployees; }
set
{
_dailyEmployees = value;
OnPropertyChanged();
}
}
public DisplayViewModel()
{
OnStatusChanged += DisplayViewModel_OnStatusChanged;
}
//invoked in other thread
private void DisplayViewModel_OnStatusChanged(object sender, EventArgs e)
{
var d = sender as Employee;
if (d == null)
return;
var em = DailyEmployees.FirstOrDefault(a => a.Name == d.Name);
if(em == null)
{
DailyEmployees.Add(em);
}
else
{
em.Status = d.Status;
}
}
}
When i tried adding values to observable collection it throws exception as
"This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"
How shall I proceed? Thanks.
Try
Application.Current.Dispatcher.BeginInvoke(() => /* update value */);
https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke(v=vs.110).aspx
Edit: see this answer
There is a big problem in your code. First, the ObservableCollection is already a collection that notifies on change, so you not need reinitialize it, just call Clear and Add/Insert.
Second, the Employee class should be ViewModelBase:
This should allow you to change
DailyEmployees[0].Status="NewStatus";
LE: In case you have problems changing data from another thread, check this link: Using BindingOperations.EnableCollectionSynchronization
LLE: I used the
ViewModelBase
class for theEmployee
, because it was already used in the code sample. A raw answer would have mean implementing theclass Employee: INotifyPropertyChanged
and implementing the required method.Either use the dispatcher to call the
Add
method on the UI thread:Or call the BindingOperations.EnableCollectionSynchronization method on the UI thread to enable the collection to be used on multiple threads:
Also note that the
Employee
class should implement theINotifyPropertyChanged
interface and raise thePropertyChanged
event for theStatus
property if you want the value of this one to be reflected in the view when you set it.