Feedback

C# - INotifyPropertyChanged Implementierung mit IsChanged Events

Veröffentlicht von am 10/12/2011
(1 Bewertungen)
Basisklasse, welche neben Benachrichtigungen durch INotifyPropertyChanged zusätzlich ein IsChanged Event für jede Property zur Verfügung stellt. Dabei werden keine string Parameter verwendet, was Probleme bei einem Refactoring vermeidet.

Beispiel Implementierung INotifyPropertyChanged:

class Person : NotificationObjectWithPropertyIsChangedEvents
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name == value) return;
_Name = value;
RaisePropertyChanged(() => Name);
}
}

public Person(string name) {
Name = name;
}
}


Beispiel Verwendung IsChanged Event:

var p = new Person("Max");
p.Property(() => p.Name).IsChanged += (s,e) => { Console.WriteLine("Neuer Name: " + (s as Person).Name); };
p.Name = "Meier";
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;

namespace eac.Utilities
{
    /// <summary>
    /// Eine Hilfsklasse, welche Events für Propery-IsChanged generisch bereit stellt
    /// obj.Property(() => obj.PROPERTY).IsChanged += (s,e) => { ... };
    /// </summary>
    public class NotificationObjectWithPropertyIsChangedEvents : Object, INotifyPropertyChanged
    {
        public sealed class NotificationObjectWithPropertyIsChangedEventHolder
        {
            public event EventHandler IsChanged;

            readonly NotificationObjectWithPropertyIsChangedEvents _obj;
            public NotificationObjectWithPropertyIsChangedEventHolder(NotificationObjectWithPropertyIsChangedEvents obj)
            {
                _obj = obj;
            }

            public void RaiseIsChanged()
            {
                var tmp = IsChanged; // in lokale variable kompieren um thread save zu sein
                if (tmp != null) tmp(_obj, EventArgs.Empty);
            }
        }

        public NotificationObjectWithPropertyIsChangedEvents()
        {
            this.PropertyChanged += NotificationObjectWithEvent_PropertyChanged;
        }

        readonly Dictionary<string, NotificationObjectWithPropertyIsChangedEventHolder> _eventHandler = new Dictionary<string, NotificationObjectWithPropertyIsChangedEventHolder>();

        public NotificationObjectWithPropertyIsChangedEventHolder Property<T>(Expression<Func<T>> propertyExpression)
        {
            var propName = ExtractPropertyName(propertyExpression);
            if (_eventHandler.ContainsKey(propName)) return _eventHandler[propName];

            var nh = new NotificationObjectWithPropertyIsChangedEventHolder(this);
            _eventHandler.Add(propName, nh);
            return nh;
        }

        void NotificationObjectWithEvent_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            foreach (var item in _eventHandler.Where(s => s.Key == e.PropertyName))
                item.Value.RaiseIsChanged();
        }

        
        // **************
        // ab hier von Prism 4.0 übernommen (http://compositewpf.codeplex.com/)

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void RaisePropertyChanged(string propertyName)
        {
            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (propertyChanged != null)
                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
        /// <summary>
        /// Raises this object's PropertyChanged event for each of the properties.
        /// </summary>
        /// <param name="propertyNames">The properties that have a new value.</param>
        protected void RaisePropertyChanged(params string[] propertyNames)
        {
            if (propertyNames == null)
                throw new System.ArgumentNullException("propertyNames");
            string[] strArrays = propertyNames;
            foreach (var str in strArrays)
                this.RaisePropertyChanged(str);
        }
        protected void RaisePropertyChanged<T>(System.Linq.Expressions.Expression<System.Func<T>> propertyExpression)
        {
            string str = ExtractPropertyName<T>(propertyExpression);
            this.RaisePropertyChanged(str);
        }
        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>        
        public virtual event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        static string ExtractPropertyName<T>(System.Linq.Expressions.Expression<System.Func<T>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new System.ArgumentNullException("propertyExpression");
            }
            System.Linq.Expressions.MemberExpression body = propertyExpression.Body as System.Linq.Expressions.MemberExpression;
            if (body == null)
            {
                throw new System.ArgumentException("The expression is not a member access expression");
            }
            System.Reflection.PropertyInfo member = body.Member as System.Reflection.PropertyInfo;
            if (member == null)
            {
                throw new System.ArgumentException("The member access expression does not access a property");
            }
            System.Reflection.MethodInfo getMethod = member.GetGetMethod(true);
            if (getMethod.IsStatic)
            {
                throw new System.ArgumentException("The referenced property is a static property");
            }
            return body.Member.Name;
        }

    }

}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!