Я настоятельно рекомендую MVVM, но когда дело доходит до иерархических моделей, подобных этой, вы можете избавить себя от горя, если захотите и сможете внести некоторые простые изменения в сами классы моделей.
Это может быстро усложниться, когда вы пишете свойства и коллекции, которые «делают недействительными» другие вычисляемые свойства. В моих приложениях я использовал подход, основанный на атрибутах, который позволяет мне украшать свойство атрибутом DependsOn, чтобы при каждом изменении зависимого свойства также вызывалось событие изменения свойства для вычисляемого свойства. В твоем случае я не думаю, что тебе нужно изо всех сил.
Но одна вещь, которая, я думаю, действительно пригодится, это класс, производный от ObservableCollection
, который из-за отсутствия лучшего термина в данный момент я назову ObservableCollectionEx
. Единственное, что он добавляет, - это событие ItemPropertyChanged
, которое позволяет подключить к нему один обработчик, и оно будет вызываться всякий раз, когда изменяется свойство элемента внутри коллекции. Это требует от вас подключения до INotifyPropertyChanged
каждый раз, когда элемент добавляется или удаляется. Но как только этот класс уходит, каскадные изменения свойств становятся легким делом.
Я бы посоветовал вам создать CarListViewModel (или как вы хотите его называть), который напоминает следующее. Обратите внимание, что конечным результатом является иерархия объектов, в которой любые изменения свойства чтения / записи Part.Total приводят к цепной реакции событий PropertyChanged, которые всплывают до ViewModel. Код ниже не является полным. Вам необходимо предоставить реализацию INotifyPropertyChanged. Но в конце вы увидите ObservableCollectionEx, о котором я упоминал.
РЕДАКТИРОВАТЬ: Я только что нажал на ссылку в вашем исходном сообщении и понял, что у вас уже есть реализация ObservableCollectionEx. Я решил использовать методы InsertItem, RemoveItem и т. Д. Вместо OnCollectionChanged, чтобы перехватить / отцепить событие элемента, потому что в другой реализации есть неприятная проблема - если вы очистите коллекцию, у вас больше не будет коллекции элементов для отсоединения.
class CarListViewModel : INotifyPropertyChanged {
public CarListViewModel() {
Cars = new ObservableCollectionEx<Car>();
Cars.CollectionChanged += (sender,e) => OnPropertyChanged("Total");
Cars.ItemPropertyChanged += (sender,e) => {
if (e.PropertyName == "Total") {
OnPropertyChanged("Total");
}
}
}
public ObservableCollectionEx<Car> Cars {
get;
private set;
}
public decimal Total {
get {
return Cars.Sum(x=>x.Total);
}
}
}
class Car : INotifyPropertyChanged {
public Car() {
Parts = new ObservableCollectionEx<Part>();
Parts.CollectionChanged += (sender,e) => OnPropertyChanged("Total");
Parts.ItemPropertyChanged += (sender,e) => {
if (e.PropertyName == "Total") {
OnPropertyChanged("Total");
}
}
}
public ObservableCollectionEx<Part> Parts {
get;
private set;
}
public decimal Total {
get {
return Parts.Sum(x=>x.Total);
}
}
}
class Part : INotifyPropertyChanged {
private decimal _Total;
public decimal Total {
get { return _Total; }
set {
_Total = value;
OnPropertyChanged("Total");
}
}
}
class ObservableCollectionEx<T> : ObservableCollection<T>
where T: INotifyPropertyChanged
{
protected override void InsertItem(int index, T item) {
base.InsertItem(index, item);
item.PropertyChanged += Item_PropertyChanged;
}
protected override void RemoveItem(int index) {
Items[index].PropertyChanged -= Item_PropertyChanged;
base.RemoveItem(index);
}
protected override void ClearItems() {
foreach (T item in Items) {
item.PropertyChanged -= Item_PropertyChanged;
}
base.ClearItems();
}
protected override void SetItem(int index, T item) {
T oldItem = Items[index];
T newItem = item;
oldItem.PropertyChanged -= Item_PropertyChanged;
newItem.PropertyChanged += Item_PropertyChanged;
base.SetItem( index, item );
}
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) {
var handler = ItemPropertyChanged;
if (handler != null) { handler(sender, e); }
}
public event PropertyChangedEventHandler ItemPropertyChanged;
}