How to update only a property in an observable collection from thread other than dispatcher thread in WPF MVVM?

前端 未结 3 501
傲寒
傲寒 2021-01-24 12:30

I am having a class named Employee. I need to update only the property Status from thread other than current dispatcher thread:

         


        
相关标签:
3条回答
  • 2021-01-24 13:01

    Either use the dispatcher to call the Add method on the UI thread:

    Application.Current.Dispatcher.BeginInvoke(() => DailyEmployees.Add(em)); 
    

    Or call the BindingOperations.EnableCollectionSynchronization method on the UI thread to enable the collection to be used on multiple threads:

    public class DisplayViewModel
    {
        private readonly ObservableCollection<Employee> _dailyEmployees = new ObservableCollection<Employee>();
        private readonly object _lock = new object();
    
        public ObservableCollection<Employee> DailyEmployees
        {
            get { return _dailyEmployees; }
        }
    
        public DisplayViewModel()
        {
            System.Windows.Data.BindingOperations.EnableCollectionSynchronization(_dailyEmployees, _lock);
            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;
            }
        }
    }
    

    Also note that the Employee class should implement the INotifyPropertyChanged interface and raise the PropertyChanged event for the Status property if you want the value of this one to be reflected in the view when you set it.

    0 讨论(0)
  • 2021-01-24 13:01

    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

    0 讨论(0)
  • 2021-01-24 13:13

    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:

    class Employee: ViewModelBase
    {
       private string _status;
    
       public string Name { get; set; }
       public string Status
       {
         get
         {
            return _status;
         }
         private set
         {
            _status=value;
           RaisePropertyChanged("Status");
         }
       }
    }
    

    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 the Employee, because it was already used in the code sample. A raw answer would have mean implementing the class Employee: INotifyPropertyChanged and implementing the required method.

    0 讨论(0)
提交回复
热议问题