Feedback

INotifyPropertyChanged Implementierung mit IsChanged Events

Sprache: C#

Basisklasse, welche neben Benachrichtigungen durch INotifyPropertyChanged zusätzlich ein IsChanged Event für jede Property zur Verfügung stellt. [b]Dabei werden keine string Parameter verwendet, was Probleme bei einem Refactoring vermeidet.[/b] [b]Beispiel Implementierung INotifyPropertyChanged:[/b] [code] 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; } } [/code] [b]Beispiel Verwendung IsChanged Event:[/b] [code] var p = new Person("Max"); p.Property(() => p.Name).IsChanged += (s,e) => { Console.WriteLine("Neuer Name: " + (s as Person).Name); }; p.Name = "Meier"; [/code]
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;
        }

    }

}
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;
        }

    }

}