Created
November 6, 2015 04:24
-
-
Save LGM-AdrianHum/08f1616de24da7eef0ba to your computer and use it in GitHub Desktop.
Yet another ViewModelBase
This file contains 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.ComponentModel; | |
using System.Diagnostics; | |
using System.Reflection; | |
using System.Collections.Specialized; | |
using System.Linq.Expressions; | |
namespace MVVMExamples | |
{ | |
/// <summary> | |
/// Base class for all ViewModel classes in the application. | |
/// It provides support for property change notifications | |
/// and has a DisplayName property. This class is abstract. | |
/// </summary> | |
public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable | |
{ | |
#region Constructor | |
protected ViewModelBase() | |
{ | |
} | |
#endregion // Constructor | |
#region DisplayName | |
/// <summary> | |
/// Returns the user-friendly name of this object. | |
/// Child classes can set this property to a new value, | |
/// or override it to determine the value on-demand. | |
/// </summary> | |
public virtual string DisplayName { get; protected set; } | |
#endregion // DisplayName | |
#region Debugging Aides | |
/// <summary> | |
/// Warns the developer if this object does not have | |
/// a public property with the specified name. This | |
/// method does not exist in a Release build. | |
/// </summary> | |
[Conditional("DEBUG")] | |
[DebuggerStepThrough] | |
public void VerifyPropertyName(string propertyName) | |
{ | |
// Verify that the property name matches a real, | |
// public, instance property on this object. | |
if (TypeDescriptor.GetProperties(this)[propertyName] == null) | |
{ | |
string msg = "Invalid property name: " + propertyName; | |
if (this.ThrowOnInvalidPropertyName) | |
throw new Exception(msg); | |
else | |
Debug.Fail(msg); | |
} | |
} | |
/// <summary> | |
/// Returns whether an exception is thrown, or if a Debug.Fail() is used | |
/// when an invalid property name is passed to the VerifyPropertyName method. | |
/// The default value is false, but subclasses used by unit tests might | |
/// override this property's getter to return true. | |
/// </summary> | |
protected virtual bool ThrowOnInvalidPropertyName { get; private set; } | |
#endregion // Debugging Aides | |
#region INotifyPropertyChanged Members | |
/// <summary> | |
/// Raised when a property on this object has a new value. | |
/// </summary> | |
public event PropertyChangedEventHandler PropertyChanged; | |
/// <summary> | |
/// Raises this object's PropertyChanged event. | |
/// </summary> | |
/// <param name="propertyName">The property that has a new value.</param> | |
protected virtual void NotifyPropertyChanged(string propertyName) | |
{ | |
this.VerifyPropertyName(propertyName); | |
PropertyChangedEventHandler handler = this.PropertyChanged; | |
if (handler != null) | |
{ | |
var e = new PropertyChangedEventArgs(propertyName); | |
handler(this, e); | |
} | |
} | |
protected virtual void NotifyPropertyChangedAll(object inOjbect) | |
{ | |
foreach (PropertyInfo pi in inOjbect.GetType().GetProperties()) | |
{ | |
NotifyPropertyChanged(pi.Name); | |
} | |
} | |
public virtual void Refresh() | |
{ | |
NotifyPropertyChangedAll(this); | |
} | |
#endregion // INotifyPropertyChanged Members | |
//http://weblogs.asp.net/fmarguerie/archive/2010/08/30/PropertyOf-INotifyPropertyChanged-PropertyChanged-strings-infoof.aspx | |
#region UpdatedNotifyPropertyChanged | |
public static PropertyInfo PropertyOf<T>(Expression<Func<T>> expression) | |
{ | |
var memberExpr = expression.Body as MemberExpression; | |
// If the method gets a lambda expression that is not a member access, | |
// for example, () => x + y, an exception is thrown | |
if (memberExpr == null) | |
throw new ArgumentException("Expression \"" + expression + | |
"\" is not a valid member expression."); | |
var property = memberExpr.Member as PropertyInfo; | |
if (property == null) | |
throw new ArgumentException("Expression \"" + expression + | |
"\" does not reference a property."); | |
return property; | |
} | |
protected void NotifyPropertyChanged<T>(Expression<Func<T>> expression) | |
{ | |
var handler = PropertyChanged; | |
if (handler == null) | |
return; | |
var propertyName = PropertyOf(expression).Name; | |
handler(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
protected void NotifyPropertyChanged() | |
{ | |
var methodName = new StackFrame(1).GetMethod().Name; | |
if (!methodName.StartsWith("set_")) | |
throw new Exception("This overload of the NotifyPropertyChanged" + | |
"method must be called from a property setter."); | |
NotifyPropertyChanged(methodName.Substring("set_".Length)); | |
} | |
#endregion | |
#region IDisposable Members | |
/// <summary> | |
/// Invoked when this object is being removed from the application | |
/// and will be subject to garbage collection. | |
/// </summary> | |
public void Dispose() | |
{ | |
this.OnDispose(); | |
} | |
/// <summary> | |
/// Child classes can override this method to perform | |
/// clean-up logic, such as removing event handlers. | |
/// </summary> | |
protected virtual void OnDispose() | |
{ | |
} | |
#if DEBUG | |
/// <summary> | |
/// Useful for ensuring that ViewModel objects are properly garbage collected. | |
/// </summary> | |
~ViewModelBase() | |
{ | |
string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode()); | |
System.Diagnostics.Debug.WriteLine(msg); | |
} | |
#endif | |
#endregion // IDisposable Members | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment