Advertisement
Guest User

ObservableObject

a guest
Jan 6th, 2014
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.82 KB | None | 0 0
  1. // ****************************************************************************
  2. // <copyright file="ObservableObject.cs" company="GalaSoft Laurent Bugnion">
  3. // Copyright © GalaSoft Laurent Bugnion 2011-2013
  4. // </copyright>
  5. // ****************************************************************************
  6. // <author>Laurent Bugnion</author>
  7. // <email>laurent@galasoft.ch</email>
  8. // <date>10.4.2011</date>
  9. // <project>GalaSoft.MvvmLight.Messaging</project>
  10. // <web>http://www.galasoft.ch</web>
  11. // <license>
  12. // See license.txt in this project or http://www.galasoft.ch/license_MIT.txt
  13. // </license>
  14. // ****************************************************************************
  15.  
  16. using System;
  17. using System.Collections.Generic;
  18. using System.ComponentModel;
  19. using System.Diagnostics;
  20. using System.Diagnostics.CodeAnalysis;
  21. using System.Reflection;
  22.  
  23. #if !SL3
  24. using System.Linq;
  25. using System.Linq.Expressions;
  26. using System.Runtime.CompilerServices;
  27.  
  28. #endif
  29.  
  30. namespace GalaSoft.MvvmLight
  31. {
  32.     /// <summary>
  33.     /// A base class for objects of which the properties must be observable.
  34.     /// </summary>
  35.     //// [ClassInfo(typeof(ViewModelBase))]
  36.     public class ObservableObject : INotifyPropertyChanged, INotifyPropertyChanging
  37.     {
  38.         /// <summary>
  39.         /// Occurs after a property value changes.
  40.         /// </summary>
  41.         public event PropertyChangedEventHandler PropertyChanged;
  42.  
  43.         /// <summary>
  44.         /// Provides access to the PropertyChanged event handler to derived classes.
  45.         /// </summary>
  46.         protected PropertyChangedEventHandler PropertyChangedHandler
  47.         {
  48.             get
  49.             {
  50.                 return PropertyChanged;
  51.             }
  52.         }
  53.  
  54.         /// <summary>
  55.         /// Occurs before a property value changes.
  56.         /// </summary>
  57.         public event PropertyChangingEventHandler PropertyChanging;
  58.  
  59.         /// <summary>
  60.         /// Provides access to the PropertyChanging event handler to derived classes.
  61.         /// </summary>
  62.         protected PropertyChangingEventHandler PropertyChangingHandler
  63.         {
  64.             get
  65.             {
  66.                 return PropertyChanging;
  67.             }
  68.         }
  69.  
  70.         /// <summary>
  71.         /// Verifies that a property name exists in this ViewModel. This method
  72.         /// can be called before the property is used, for instance before
  73.         /// calling RaisePropertyChanged. It avoids errors when a property name
  74.         /// is changed but some places are missed.
  75.         /// </summary>
  76.         /// <remarks>This method is only active in DEBUG mode.</remarks>
  77.         /// <param name="propertyName">The name of the property that will be
  78.         /// checked.</param>
  79.         [Conditional("DEBUG")]
  80.         [DebuggerStepThrough]
  81.         public void VerifyPropertyName(string propertyName)
  82.         {
  83.             var myType = GetType();
  84.  
  85. #if NETFX_CORE
  86.             if (!string.IsNullOrEmpty(propertyName)
  87.                 && myType.GetTypeInfo().GetDeclaredProperty(propertyName) == null)
  88.             {
  89.                 throw new ArgumentException("Property not found", propertyName);
  90.             }
  91. #else
  92.             if (!string.IsNullOrEmpty(propertyName)
  93.                 && myType.GetProperty(propertyName) == null)
  94.             {
  95. #if !SILVERLIGHT
  96.                 var descriptor = this as ICustomTypeDescriptor;
  97.  
  98.                 if (descriptor != null)
  99.                 {
  100.                     if (descriptor.GetProperties()
  101.                         .Cast<PropertyDescriptor>()
  102.                         .Any(property => property.Name == propertyName))
  103.                     {
  104.                         return;
  105.                     }
  106.                 }
  107. #endif
  108.  
  109.                 throw new ArgumentException("Property not found", propertyName);
  110.             }
  111. #endif
  112.         }
  113.  
  114. #if CMNATTR
  115.         /// <summary>
  116.         /// Raises the PropertyChanging event if needed.
  117.         /// </summary>
  118.         /// <remarks>If the propertyName parameter
  119.         /// does not correspond to an existing property on the current class, an
  120.         /// exception is thrown in DEBUG configuration only.</remarks>
  121.         /// <param name="propertyName">(optional) The name of the property that
  122.         /// changed.</param>
  123.         [SuppressMessage(
  124.             "Microsoft.Design",
  125.             "CA1030:UseEventsWhereAppropriate",
  126.             Justification = "This cannot be an event")]
  127.         protected virtual void RaisePropertyChanging(
  128.             [CallerMemberName] string propertyName = null)
  129. #else
  130.         /// <summary>
  131.         /// Raises the PropertyChanging event if needed.
  132.         /// </summary>
  133.         /// <remarks>If the propertyName parameter
  134.         /// does not correspond to an existing property on the current class, an
  135.         /// exception is thrown in DEBUG configuration only.</remarks>
  136.         /// <param name="propertyName">The name of the property that
  137.         /// changed.</param>
  138.         [SuppressMessage(
  139.             "Microsoft.Design",
  140.             "CA1030:UseEventsWhereAppropriate",
  141.             Justification = "This cannot be an event")]
  142.         protected virtual void RaisePropertyChanging(
  143.             string propertyName)
  144. #endif
  145.         {
  146.             VerifyPropertyName(propertyName);
  147.  
  148.             var handler = PropertyChanging;
  149.             if (handler != null)
  150.             {
  151.                 handler(this, new PropertyChangingEventArgs(propertyName));
  152.             }
  153.         }
  154.  
  155. #if CMNATTR
  156.         /// <summary>
  157.         /// Raises the PropertyChanged event if needed.
  158.         /// </summary>
  159.         /// <remarks>If the propertyName parameter
  160.         /// does not correspond to an existing property on the current class, an
  161.         /// exception is thrown in DEBUG configuration only.</remarks>
  162.         /// <param name="propertyName">(optional) The name of the property that
  163.         /// changed.</param>
  164.         [SuppressMessage(
  165.             "Microsoft.Design",
  166.             "CA1030:UseEventsWhereAppropriate",
  167.             Justification = "This cannot be an event")]
  168.         protected virtual void RaisePropertyChanged(
  169.             [CallerMemberName] string propertyName = null)
  170. #else
  171.         /// <summary>
  172.         /// Raises the PropertyChanged event if needed.
  173.         /// </summary>
  174.         /// <remarks>If the propertyName parameter
  175.         /// does not correspond to an existing property on the current class, an
  176.         /// exception is thrown in DEBUG configuration only.</remarks>
  177.         /// <param name="propertyName">The name of the property that
  178.         /// changed.</param>
  179.         [SuppressMessage(
  180.             "Microsoft.Design",
  181.             "CA1030:UseEventsWhereAppropriate",
  182.             Justification = "This cannot be an event")]
  183.         protected virtual void RaisePropertyChanged(
  184.             string propertyName)
  185. #endif
  186.         {
  187.             VerifyPropertyName(propertyName);
  188.  
  189.             var handler = PropertyChanged;
  190.             if (handler != null)
  191.             {
  192.                 handler(this, new PropertyChangedEventArgs(propertyName));
  193.             }
  194.         }
  195.  
  196. #if !SL3
  197.         /// <summary>
  198.         /// Raises the PropertyChanging event if needed.
  199.         /// </summary>
  200.         /// <typeparam name="T">The type of the property that
  201.         /// changes.</typeparam>
  202.         /// <param name="propertyExpression">An expression identifying the property
  203.         /// that changes.</param>
  204.         [SuppressMessage(
  205.             "Microsoft.Design",
  206.             "CA1030:UseEventsWhereAppropriate",
  207.             Justification = "This cannot be an event")]
  208.         [SuppressMessage(
  209.             "Microsoft.Design",
  210.             "CA1006:GenericMethodsShouldProvideTypeParameter",
  211.             Justification = "This syntax is more convenient than other alternatives.")]
  212.         protected virtual void RaisePropertyChanging<T>(Expression<Func<T>> propertyExpression)
  213.         {
  214.             var handler = PropertyChanging;
  215.             if (handler != null)
  216.             {
  217.                 var propertyName = GetPropertyName(propertyExpression);
  218.                 handler(this, new PropertyChangingEventArgs(propertyName));
  219.             }
  220.         }
  221.  
  222.         /// <summary>
  223.         /// Raises the PropertyChanged event if needed.
  224.         /// </summary>
  225.         /// <typeparam name="T">The type of the property that
  226.         /// changed.</typeparam>
  227.         /// <param name="propertyExpression">An expression identifying the property
  228.         /// that changed.</param>
  229.         [SuppressMessage(
  230.             "Microsoft.Design",
  231.             "CA1030:UseEventsWhereAppropriate",
  232.             Justification = "This cannot be an event")]
  233.         [SuppressMessage(
  234.             "Microsoft.Design",
  235.             "CA1006:GenericMethodsShouldProvideTypeParameter",
  236.             Justification = "This syntax is more convenient than other alternatives.")]
  237.         protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
  238.         {
  239.             var handler = PropertyChanged;
  240.             if (handler != null)
  241.             {
  242.                 var propertyName = GetPropertyName(propertyExpression);
  243.                 handler(this, new PropertyChangedEventArgs(propertyName));
  244.             }
  245.         }
  246.  
  247.         /// <summary>
  248.         /// Extracts the name of a property from an expression.
  249.         /// </summary>
  250.         /// <typeparam name="T">The type of the property.</typeparam>
  251.         /// <param name="propertyExpression">An expression returning the property's name.</param>
  252.         /// <returns>The name of the property returned by the expression.</returns>
  253.         /// <exception cref="ArgumentNullException">If the expression is null.</exception>
  254.         /// <exception cref="ArgumentException">If the expression does not represent a property.</exception>
  255.         [SuppressMessage(
  256.             "Microsoft.Design",
  257.             "CA1011:ConsiderPassingBaseTypesAsParameters",
  258.             Justification = "This syntax is more convenient than the alternatives."),
  259.          SuppressMessage(
  260.             "Microsoft.Design",
  261.             "CA1006:DoNotNestGenericTypesInMemberSignatures",
  262.             Justification = "This syntax is more convenient than the alternatives.")]
  263.         protected static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
  264.         {
  265.             if (propertyExpression == null)
  266.             {
  267.                 throw new ArgumentNullException("propertyExpression");
  268.             }
  269.  
  270.             var body = propertyExpression.Body as MemberExpression;
  271.  
  272.             if (body == null)
  273.             {
  274.                 throw new ArgumentException("Invalid argument", "propertyExpression");
  275.             }
  276.  
  277.             var property = body.Member as PropertyInfo;
  278.  
  279.             if (property == null)
  280.             {
  281.                 throw new ArgumentException("Argument is not a property", "propertyExpression");
  282.             }
  283.  
  284.             return property.Name;
  285.         }
  286.  
  287.         /// <summary>
  288.         /// Assigns a new value to the property. Then, raises the
  289.         /// PropertyChanged event if needed.
  290.         /// </summary>
  291.         /// <typeparam name="T">The type of the property that
  292.         /// changed.</typeparam>
  293.         /// <param name="propertyExpression">An expression identifying the property
  294.         /// that changed.</param>
  295.         /// <param name="field">The field storing the property's value.</param>
  296.         /// <param name="newValue">The property's value after the change
  297.         /// occurred.</param>
  298.         /// <returns>True if the PropertyChanged event has been raised,
  299.         /// false otherwise. The event is not raised if the old
  300.         /// value is equal to the new value.</returns>
  301.         [SuppressMessage(
  302.             "Microsoft.Design",
  303.             "CA1006:DoNotNestGenericTypesInMemberSignatures",
  304.             Justification = "This syntax is more convenient than the alternatives."),
  305.          SuppressMessage(
  306.             "Microsoft.Design",
  307.             "CA1045:DoNotPassTypesByReference",
  308.             MessageId = "1#",
  309.             Justification = "This syntax is more convenient than the alternatives.")]
  310.         protected bool Set<T>(
  311.             Expression<Func<T>> propertyExpression,
  312.             ref T field,
  313.             T newValue)
  314.         {
  315.             if (EqualityComparer<T>.Default.Equals(field, newValue))
  316.             {
  317.                 return false;
  318.             }
  319.  
  320.             RaisePropertyChanging(propertyExpression);
  321.             field = newValue;
  322.             RaisePropertyChanged(propertyExpression);
  323.             return true;
  324.         }
  325.  
  326.         /// <summary>
  327.         /// Assigns a new value to the property. Then, raises the
  328.         /// PropertyChanged event if needed.
  329.         /// </summary>
  330.         /// <typeparam name="T">The type of the property that
  331.         /// changed.</typeparam>
  332.         /// <param name="propertyName">The name of the property that
  333.         /// changed.</param>
  334.         /// <param name="field">The field storing the property's value.</param>
  335.         /// <param name="newValue">The property's value after the change
  336.         /// occurred.</param>
  337.         /// <returns>True if the PropertyChanged event has been raised,
  338.         /// false otherwise. The event is not raised if the old
  339.         /// value is equal to the new value.</returns>
  340.         [SuppressMessage(
  341.             "Microsoft.Design",
  342.             "CA1045:DoNotPassTypesByReference",
  343.             MessageId = "1#",
  344.             Justification = "This syntax is more convenient than the alternatives.")]
  345.         protected bool Set<T>(
  346.             string propertyName,
  347.             ref T field,
  348.             T newValue)
  349.         {
  350.             if (EqualityComparer<T>.Default.Equals(field, newValue))
  351.             {
  352.                 return false;
  353.             }
  354.  
  355.             RaisePropertyChanging(propertyName);
  356.             field = newValue;
  357.             RaisePropertyChanged(propertyName);
  358.             return true;
  359.         }
  360. #endif
  361.  
  362. #if CMNATTR
  363.         /// <summary>
  364.         /// Assigns a new value to the property. Then, raises the
  365.         /// PropertyChanged event if needed.
  366.         /// </summary>
  367.         /// <typeparam name="T">The type of the property that
  368.         /// changed.</typeparam>
  369.         /// <param name="field">The field storing the property's value.</param>
  370.         /// <param name="newValue">The property's value after the change
  371.         /// occurred.</param>
  372.         /// <param name="propertyName">(optional) The name of the property that
  373.         /// changed.</param>
  374.         /// <returns>True if the PropertyChanged event has been raised,
  375.         /// false otherwise. The event is not raised if the old
  376.         /// value is equal to the new value.</returns>
  377.         protected bool Set<T>(
  378.             ref T field,
  379.             T newValue,
  380.             [CallerMemberName] string propertyName = null)
  381.         {
  382.             return Set(propertyName, ref field, newValue);
  383.         }
  384. #endif
  385.     }
  386. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement