MVVM属性取决于对象图

时间:2011-12-06 16:01:34

标签: c# wpf data-binding mvvm observablecollection

我正在使用WPF+MVVM

我有VM,其中包含Customer属性。 Customer的{​​{1}} ObservableCollection。每个Orders都有Order ObservableCollection。每个Items都有Items

现在,我的Price上有以下属性:

VM

问题在于,此对象图中的任何位置都发生了更改 - 应通知用户界面public double TotalPrice { return Customer.Orders.Sum(x => x.Items.Sum(y => y.Price)); } 已更改 - 但它不会...

例如,如果TotalPrice将从A更改为B,或者将添加订单,或者项目将被删除,或者项目的价格将被更改等等。

有没有人有这个优雅的解决方案?

感谢。

4 个答案:

答案 0 :(得分:3)

您是否支持ViewModels中的INotifyPropertyChanged / INotifyCollectionChanged接口?您应该能够手动触发任何属性,例如在可以触发OnPropertyChanged("TotalPrice")的任何属性的setter中,因此TotalPrice的UI绑定也会更新。

要处理依赖对象更改,您可以提供事件或其他类似的东西,以便ViewModel能够订阅和处理底层对象更改,例如,您有一些服务可以从数据库重新加载Orders,以便随着新变化的到来,你也会更新UI。在这种情况下,OrdersService应公开event OrdersUpdated,ViewModel可以订阅此事件,并在受影响的属性的触发PropertyChanged事件中进行订阅。

让我们以某个案例为例,例如订单价格已经改变。谁负责这种变化?这是由用户通过UI完成的吗?

答案 1 :(得分:1)

你可以找到here几天前我写的一篇有趣的帖子,它正好谈到了这个问题(及其解决方案......)

答案 2 :(得分:0)

您可以实现“accumulator”属性,该属性将值的总和存储在对象集合中。听取对这些值的更改并适当更新累加器 (顺便说一句 - 我忘了提到这个实际上只适用于计算价值昂贵的情况。否则Sll的答案肯定是要走的路。)

像这样的事情,遗漏了无聊的东西:

    class BasketOfGoods : INotifyPropertyChanged
{
    ObservableCollection<Good> contents = new ObservableCollection<Good>();

    public decimal Total
    {
        get { /* getter code */ }
        set { /*setter code */ }
    }

    public BasketOfGoods()
    {
        contents.CollectionChanged += contents_CollectionChanged;
    }

    void contents_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        foreach (var newGood in e.NewItems) ((Good)newGood).PropertyChanged += BasketOfGoods_PropertyChanged;
    }

    void BasketOfGoods_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Price") Total = contents.Select(x => x.Price).Sum();
    }

}

class Good : INotifyPropertyChanged
{
    public decimal Price
    {
    {
        get { /* getter code */ }
        set { /*setter code */ }
    }
}

答案 3 :(得分:0)

我认为我最新的WPF努力MadProps很好地处理了这种情况。看看this example master-detail scenario。只要存在从正在编辑的项目到VM的路径(例如,VM.TheCustomer.SelectedOrder.SelectedItem或简称VM.SelectedItem),PropChanged事件将传播到VM,您可以写:

public readonly IProp<Customer> TheCustomer;
public readonly IProp<double> TotalPrice;

protected override void OnPropChanged(PropChangedEventArgs args)
{
    if (args.Prop.IsAny(TheCustomer, Item.Schema.Price))
    {
        TotalPrice.Value = TheCustomer.Value.Orders
            .Sum(order => order.Items.Sum(item => item.Price.Value));
    }
}

关于添加和删除项目或订单,我只会在ICommand代码中添加一个明确的更新,例如VM.UpdateTotalPrice();。管理ObservableCollections的订阅和取消订阅以及其中的项目可能很棘手。