ObservableCollection中的ObservableCollection会触发Collection更改事件

时间:2016-12-21 20:38:52

标签: c# wpf xaml uwp observablecollection

在过去的三天里,我一直面临着一个非常复杂的问题。我正在尝试订购应用程序,为此我想要一个包含MainCategory项目的ObservableCollection。现在,MainCategory项目包含一个CategoryName和另一个ObservableCollection菜肴。菜肴有这些道具:名称,价格和数量。我做了所有这些,绑定和一切都很完美。

问题出现在页面底部(ListView外部嵌套在Listview中)我想要一个带有TotalValue的TextBlock,每次需要更改菜肴的数量。我正在使用MVVM,我已经完成了对props和CollectionChanged的所有INotifyPropertyChanged,但这仅在我添加或删除某些内容时有效。当我在第二个ObservableCollection中改变道具的值时,不是这样。

以下是一些代码:

    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");
            }
        }
    }

}

我只想找到一种方法,以便在Main observable集合中发生任何变化时保持我的总值更新,例如产品的数量。无论如何都要解雇CollectionChanged事件?

这是用户界面 this is the UI

和没有按钮的早期版本 and an earlier version without the buttons

2 个答案:

答案 0 :(得分:1)

如果在集合中的项目发生变化时需要更新,我会考虑不使用可观察集合。可观察集合仅用于在集合中添加或删除项目时注意。

我之前做过的事情与下面的代码相似。

MainCategory中,您只会公开IEnumerable<Dish>而不是完整列表。然后,在MainCategory中,您可以创建包装方法来添加和删除订阅属性更改通知的菜肴。然后,每当菜肴发生变化时,您都可以更新总计值,并通知您的菜肴列表已更改。

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");
}

答案 1 :(得分:1)

另一个可能对你有用的选择是我几年前在网上买的并且非常方便。它被称为“真正”可观察的集合,不仅会在添加/删除项目时触发事件,而且还会在列表中项目的属性发生变化时触发事件。我没有在集合中尝试使用它,但它应该可以工作

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);
        }
    }
}