Reputation: 697
I'd like to have methodToBeCalledWhenPropertyIsSet() execute when Property in the Model is changed.
How could I do this?
If I understand correctly, I could add MyModel.PropertyChanged += methodToBeCalledWhenPropertyIsSet
somewhere in my ViewModel to subscribe to the PropertyChanged event in general but I only care when Property is set
public class ViewModel : INotifyPropertyChanged
{
...
public Model MyModel { get; set; }
public void methodToBeCalledWhenPropertyIsSet() { }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Model : INotifyPropertyChanged
{
object _propertyField;
public object Property
{
get
{
return _propertyField;
}
set
{
_propertyField = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 6
Views: 16713
Reputation: 44038
One possible, commonly used solution is to wrap the Model's Property
with an equivalent property in the ViewModel:
public class ViewModel
{
public object Property
{
get
{
return Model.Property;
}
set
{
Model.Property = value;
methodToBeCalledWhenPropertyIsSet(); // Here you call your method directly
}
}
}
And bind your UI to this property rather than the Model's.
Edit: If the model changes due to UI interaction, then that interaction will occur "thru" the ViewModel. If the model changes due to internal business logic in the model itself, then you'll have no other option but to subscribe to it's PropertyChanged
event, but make sure you properly unsubscribe at a later moment. I usually put such subscription / unsubscription code In the setter of the Model
property in the VM:
public MyModel Model
{
get { return _model; }
set
{
if (_model != null)
_model.PropertyChanged -= OnModelPropertyChanged;
_model = value;
if (_model != null
_model.PropertyChanged += OnModelPropertyChanged;
NotifyPropertyChange(() => Model);
}
}
Upvotes: 3
Reputation: 351
The INotifyPropertyChanged interface solves this problem. Subscribe your View Model to the Models PropertyChangedEventHandler and filter your results.
public class ViewModel : INotifyPropertyChanged
{
...
public Model MyModel { get; set; }
public void methodToBeCalledWhenPropertyIsSet() { }
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
// MyModel would need to be set in this example.
MyModel.PropertyChanged += Model_PropertyChanged;
}
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Property")
{
methodToBeCalledWhenPropertyIsSet();
}
}
}
In the MVVM pattern the View Model is intended to deal with messy situations like this. This still maintains your abstraction from the model.
Edit As HighCore pointed out, this code doesn't work copy paste. MyModel would need to be instantiated beforehand. I use MEF(http://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx) for this purpose. You can either grab a model class directly or use some kind of factory/manager to get a reference.
Upvotes: 14