Last active
March 28, 2020 22:22
-
-
Save makomweb/a761768a5b16e4ca2740 to your computer and use it in GitHub Desktop.
This is a view model base implementation which can be used in well known MVVM scenarios. It stores all the values in a backing dictionary and accesses it through the property name specified by the lambda expression.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Diagnostics; | |
using System.Linq.Expressions; | |
namespace Playground { | |
// Notice the 3 occurrencies of the Title identifier and the abscence of additional backing fields! | |
public class ExampleViewModel : ViewModelBase { | |
public string Title { | |
get { return GetValue(() => Title); } | |
set { SetValue(() => Title, value); } | |
} | |
} | |
public abstract class ViewModelBase : INotifyPropertyChanged { | |
private readonly Dictionary<string, object> _propertyValueStorage = new Dictionary<string, object>(); | |
public event PropertyChangedEventHandler PropertyChanged; | |
protected T GetValue<T>(Expression<Func<T>> property) { | |
var expression = property as LambdaExpression; | |
if (expression == null) { | |
throw new ArgumentException("The property is not a valid lambda expression!", "property"); | |
} | |
var propertyName = ExtractPropertyName(expression); | |
return GetValue<T>(propertyName); | |
} | |
private T GetValue<T>(string propertyName) { | |
object value; | |
if (_propertyValueStorage.TryGetValue(propertyName, out value)) { | |
return (T) value; | |
} | |
return default(T); | |
} | |
protected void SetValue<T>(Expression<Func<T>> property, T value) { | |
var expression = property as LambdaExpression; | |
if (expression == null) { | |
throw new ArgumentException("The property is not a valid lambda expression!", "property"); | |
} | |
var propertyName = ExtractPropertyName(expression); | |
var currentValue = GetValue<T>(propertyName); | |
if (Equals(currentValue, value)) | |
return; | |
_propertyValueStorage[propertyName] = value; | |
if (PropertyChanged != null) { | |
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
} | |
protected void RaisePropertyChanged() { | |
if (PropertyChanged == null) | |
return; | |
var stackTrace = new StackTrace(); | |
var callingMethodName = stackTrace.GetFrame(1).GetMethod().Name; | |
if (!callingMethodName.Contains("_")) | |
return; | |
var propertyName = callingMethodName.Split('_')[1]; | |
if (!string.IsNullOrEmpty(propertyName)) { | |
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
} | |
protected void RaisePropertyChanged(Expression<Func<object>> expression) { | |
if (PropertyChanged == null) | |
return; | |
var body = expression.Body as MemberExpression; | |
if (body == null && expression.Body is UnaryExpression) { | |
var unaryExpression = expression.Body as UnaryExpression; | |
body = unaryExpression.Operand as MemberExpression; | |
} | |
PropertyChanged(this, new PropertyChangedEventArgs(body.Member.Name)); | |
} | |
[Obsolete("Use the overload which takes a lambda instead!")] | |
protected void RaisePropertyChanged(string propertyName) { | |
AssertPropertyExistence(propertyName); | |
if (PropertyChanged != null) { | |
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
} | |
[Conditional("DEBUG")] | |
private void AssertPropertyExistence(string propertyName) { | |
var propertyDescriptor = TypeDescriptor.GetProperties(this)[propertyName]; | |
if (propertyDescriptor == null) { | |
#if true | |
Debug.Fail(string.Format("The property with the propertyName '{0}' doesn't exist.", propertyName)); | |
#else | |
throw new InvalidOperationException(string.Format("The property with the propertyName '{0}' doesn't exist.", propertyName)); | |
#endif | |
} | |
} | |
private static string ExtractPropertyName(LambdaExpression expression) { | |
MemberExpression memberExpression; | |
if (expression.Body is UnaryExpression) { | |
var unaryExpression = expression.Body as UnaryExpression; | |
memberExpression = unaryExpression.Operand as MemberExpression; | |
} | |
else { | |
memberExpression = expression.Body as MemberExpression; | |
} | |
return memberExpression.Member.Name; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment