I am going through some MVVM articles, primarily this and this.
My specific question is: How do I communicate Model changes from the Model to the ViewModel?<
Fairly old thread but after a lot of searching I came up with my own solution: A PropertyChangedProxy
With this class, you can easily register to someone else's NotifyPropertyChanged and take appropriate actions if it is fired for the registered property.
Here's a sample of how this could look like when you have a model property "Status" which can change on it's own and then should automatically notify the ViewModel to fire it's own PropertyChanged on it's "Status" property so that the view is also notified :)
public class MyModel : INotifyPropertyChanged
{
private string _status;
public string Status
{
get { return _status; }
set { _status = value; OnPropertyChanged(); }
}
// Default INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MyViewModel : INotifyPropertyChanged
{
public string Status
{
get { return _model.Status; }
}
private PropertyChangedProxy _statusPropertyChangedProxy;
private MyModel _model;
public MyViewModel(MyModel model)
{
_model = model;
_statusPropertyChangedProxy = new PropertyChangedProxy(
_model, myModel => myModel.Status, s => OnPropertyChanged("Status")
);
}
// Default INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
and here's the class itself:
///
/// Proxy class to easily take actions when a specific property in the "source" changed
///
/// Last updated: 20.01.2015
/// Type of the source
/// Type of the property
public class PropertyChangedProxy where TSource : INotifyPropertyChanged
{
private readonly Func _getValueFunc;
private readonly TSource _source;
private readonly Action _onPropertyChanged;
private readonly string _modelPropertyname;
///
/// Constructor for a property changed proxy
///
/// The source object to listen for property changes
/// Expression to the property of the source
/// Action to take when a property changed was fired
public PropertyChangedProxy(TSource source, Expression> selectorExpression, Action onPropertyChanged)
{
_source = source;
_onPropertyChanged = onPropertyChanged;
// Property "getter" to get the value
_getValueFunc = selectorExpression.Compile();
// Name of the property
var body = (MemberExpression)selectorExpression.Body;
_modelPropertyname = body.Member.Name;
// Changed event
_source.PropertyChanged += SourcePropertyChanged;
}
private void SourcePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == _modelPropertyname)
{
_onPropertyChanged(_getValueFunc(_source));
}
}
}