ObservableCollection inside ObservableCollection doen't fire Collection changed event

左心房为你撑大大i 提交于 2019-12-25 08:13:22

问题


For the last three days I've been facing a quite a composite problem. I am trying to make an order taking app, to do this I wanted to have an ObservableCollection containing MainCategory items. Now the MainCategory items contained a CategoryName and another ObservableCollection of dishes. The dishes have those props: name, price and quantity. I did all this and the bindings and everything works perfectly.

The problem is at the bottom of the page (outside the ListView which is nested inside a Listview ) I want to have a TextBlock with the TotalValue that needs to change every time The quantity of a dish changes. I am using MVVM and I have done all the INotifyPropertyChanged to the props and the CollectionChanged, but this only works when I add or remove something. Not when I change the value of a prop in the second ObservableCollection.

Here is some code:

    public class MenuCollection : ObservableCollection<MainCategories>,
INotifyCollectionChanged, INotifyPropertyChanged
{
    public MenuCollection()
    {
        Add(new MainCategories("Category1", false));
        this[0].SubMenuItems.Add(new Dishes("Dish1", 4));

    }
}

 public class MainCategories : MainViewModelBase
{

    public ObservableCollection<Dishes> SubMenuItems{get; set;}  
    public MainCategories(string name, bool visible)
    {
        this.categoryName = name;
        this.visible = visible;
        SubMenuItems = new ObservableCollection<Dishes>();
    }

    public string categoryName;
    public string CategoryName
    {
        get { return categoryName; }
        set
        {
            if (categoryName != value)
            {
                categoryName = value;
                OnPropertyChanged("CategoryName");
            }
        }
    }
    public bool visible;
    public bool Visible
    {
        get { return visible; }
        set
        {
            if (visible != value)
            {
                visible = value;
                OnPropertyChanged("Visible");
            }
        }
    }
}

public class Dishes : MainViewModelBase
{
    public Dishes(string dishName, int price)
    {
        this.dishName = dishName;
        this.dishPrice = price;
        this.quantity = 0;
    }

    private string dishName;
    public string DishName
    {
        get { return dishName; }
        set
        {
            if (dishName != value)
            {
                dishName = value;
                OnPropertyChanged("DishName");
            }
        }
    }
    private int dishPrice;
    public int DishPrice
    {
        get { return dishPrice; }
        set
        {
            if (dishPrice != value)
            {
                dishPrice = value;
                OnPropertyChanged("DishPrice");
            }
        }
    }
    private int quantity;
    public int Quantity
    {
        get { return quantity; }
        set
        {
            if (quantity != value)
            {
                quantity = value;
                OnPropertyChanged("Quantity");
            }
        }
    }

}

I just want to find a way to keep my total value update when anything changes inside the Main observable collection, like the quantity of a product. is there anyway to fire the CollectionChanged event?

this is the UI

and an earlier version without the buttons


回答1:


I would consider possibly not using an observable collection if you need updates when items in the collection change. Observable collection is only useful for noting when items are added or removed from a collection.

Something that I've done before is similar to the code below.

In your MainCategory you would only expose an IEnumerable<Dish> instead of the full list. Then, in MainCategory you can create wrapping methods to add and remove dishes that subscribe to property changed notifications. Then every time a dish changes you can make updates to your aggregate values like Total and notify that your list of dishes has changed.

private List<Dish> _subMenuItems = new List<Dish>();
public IEnumerable<Dish> SubMenuItems { get { return _subMenuItems; } }

public void AddDish(Dish dish)
{
    _subMenuItems.Add(dish);
    dish.PropertyChanged += dish_PropertyChanged;
    OnPropertyChanged("SubMenuItems");
}

public void RemoveDish(Dish dish)
{
    if (_subMenuItems.Contains(dish))
    {
        dish.PropertyChanged -= dish_PropertyChanged;
        _subMenuItems.Remove(dish);
        OnPropertyChanged("SubMenuItems");
    }
}

private double _total;
public double Total
{
    get { return _total; }
    set
    {
        if (_total != value)
        {
            _total = value;
            OnPropertyChanged("Total");
        }
    }
}

private void dish_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Total = getTotal();
    // any other aggregate calculations can go here.
    OnPropertyChanged("SubMenuItems");
}



回答2:


Another option that might work for you is something I picked up online a few years ago and is quite handy. It is call a "Truly" observable collection and will fire events not only when items are added/removed but also when properties on the items within the list change. I havent tried it with a collection within a collection but it should work

public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler ItemPropertyChanged;

    public TrulyObservableCollection()
        : base()
    {
        CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
    }

    public TrulyObservableCollection(IEnumerable<T> pItems)
        : this()
    {
        foreach (var item in pItems)
        {
            this.Add(item);
        }
    }

    void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
        OnCollectionChanged(a);

        if (ItemPropertyChanged != null)
        {
            ItemPropertyChanged(sender, e);
        }
    }
}


来源:https://stackoverflow.com/questions/41271513/observablecollection-inside-observablecollection-doent-fire-collection-changed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!