简体   繁体   中英

How can I notify that a property of an item in an observable collection has changed?

Okay, I have an ItemsControl in a XAML file that binds to an ObservableCollection. The ObservableCollection is found on a view-model class (let's call this class ViewModelA), and each item in the ObservableCollection is an instance of another view-model class (let's call the class ViewModelB).

There is a property on ViewModelA, that, when changed, will indirectly change the values of properties found in many instances of the ViewModelB class. In other words, it doesn't go straight to ViewModelB and set its properties, thus causing an INotifyPropertyChange call, but rather goes down to the model, sets some property in my model, and that change in my model affects what ViewModelB should be showing the view.

How can I notify the view that something in ViewModelB has changed?

You should be able to tell the View that the collection has changed, and in turn, trigger it to rebind to the entire collection (which would update the View).

If your Model implements INotifyPropertyChanged , the other option would be to have your ViewModelB class listen for changes on it's wrapped Model, and raise property changed events as needed.

Ideally, you'd be able to do like Reed Copsey indicated... Implement INotifyPropertyChanged on the model and have ViewModelB listen for those events. Then ViewModelB will pick up the changes no matter where the update happens.

However, In some cases the model doesn't (or can't) implement INotifyPropertyChanged. In this case, you may want to consider using an Event Aggregator pattern to pass a message between ViewModelA and the ViewModelB instances.

In this case, you could publish a "model changed" message from ViewModelA. The ViewModelB instances would subscribe to this message and each of them would get notified when A published the message. Then ViewModelB could raise the approriate PropertyChanged events to tell the UI what's changed.

You can find more info on Event Aggregator in many of the frameworks, including

To solve this I created a class called VeryObservableCollection. For each object you add, it hooks the object's NotifyPropertyChanged event to a handler that triggers a CollectionChanged event. For each object removed, it removes the handler. Very simple and will give you exactly what you want. Partial code:

public class VeryObservableCollection<T> : ObservableCollection<T>

/// <summary>
/// Override for setting item
/// </summary>
/// <param name="index">Index</param>
/// <param name="item">Item</param>
protected override void SetItem(int index, T item)
{
    try
    {
        INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged;
        if (propOld != null)
            propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged);
    }
    catch (Exception ex)
    {
        Exception ex2 = ex.InnerException;
    }
    INotifyPropertyChanged propNew = item as INotifyPropertyChanged;
    if (propNew != null)
        propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged);

    base.SetItem(index, item);
}

If change in Models will change in some properties of ViewModelB and those properties has change notification to UI (ie ViewModleB is implementing INotifyPropertyChanged), the change will immediately reflect in the UI.

So, if you have a ObservableCollection of another viewmodelB, you need not to hook up events for the propertychanged of that viewmodelB. According to my understanding, whoever changes viewmodelB's properties (model class or anyone else) and if the properties has change notification, the view will update automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM