我正在使用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,或者将添加订单,或者项目将被删除,或者项目的价格将被更改等等。
有没有人有这个优雅的解决方案?
感谢。
答案 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的订阅和取消订阅以及其中的项目可能很棘手。