问题
My simplified program structure looks like this:
public class Manager
{
public Item MyItem { get; set; }
public void Recalculate(){ ... }
}
public class Item
{
public string SomeProperty { get; set; }
}
public class ManagerViewModel
{
public Manager Model { get; set; }
public ItemViewModel MyItem { get; set; }
}
public class ItemViewModel
{
public Item Model { get; set; }
public string SomeProperty
{
get => Model.SomeProperty;
set
{
Model.SomeProperty = value;
RaisePropertyChanged("SomeProperty");
}
}
}
When SomeProperty
gets changed in ItemViewModel
, I want Recalculate()
to get triggered inside Manager.
Do I:
A) Have a PropertyChangedListener inside ManagerViewModel
which listens for Property changes inside it's MyItem
, and then tells it's Model to Recalculate()
B) Allow ItemViewModel to have access to Manager, so it can manually tell Manager to run Recalculate()
..
(B) seems kind of anti-pattern-ish... shouldn't each ViewModel only really be concerned with it's own Model? (A) has it's own issues -- I need to use this sort of 'Recalculation' structure a lot, and it seems having these PropertyChangedListeners all over the place is kind of messy. I realise there's a few different ways of going about this, but I'm just wondering what the 'best practice' is in this case.
回答1:
As confirmed by Ed Plunkett, 'option A' is the best approach, as it separates the concerns of the ViewModels and Models.
ItemViewModel
is only concerned with it's own Model, and it just notifies whoever's listening that it's properties have been changed.
ManagerViewModel
listens for changes inside ItemViewModel
, and then executes Recalculate()
inside it's own model.
//Models
public class Manager
{
public Item MyItem { get; set; }
public void Recalculate(){ ... }
}
public class Item
{
public string SomeProperty { get; set; }
}
//ViewModels
public class ManagerViewModel
{
public Manager Model { get; set; }
public ItemViewModel MyItem { get; set; }
public ManagerViewModel()
{
//Listen for property changes inside MyItem
MyItem.PropertyChanged += ItemPropertyChanged;
}
//Whenever a Property gets updated inside MyItem, run Recalculate() inside the Manager Model
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
Model.Recalculate();
}
}
public class ItemViewModel
{
public Item Model { get; set; }
public string SomeProperty
{
get => Model.SomeProperty;
set
{
Model.SomeProperty = value;
RaisePropertyChanged("SomeProperty");
}
}
}
回答2:
There's nothing wrong with making your Model(s) observable by adding INotifyPropertyChanged to them also. Then you can listen to the models you're bound to. In many projects I prefer to have a static data set layer, which publishes the list of models from a store and those models are all observable. This means they can be bound to and since the store is the same source any ViewModels etc can bind to them and become updated system wide. Looks like you're on the right track so don't second guess yourself. Making things observable, downright to the model, isn't bad or considered bad practice. I personally prefer it.
来源:https://stackoverflow.com/questions/46984421/mvvm-best-practices-communication-between-view-models