How to raise PropertyChanged event without using string name

后端 未结 8 1329
后悔当初
后悔当初 2020-11-29 00:22

It would be good to have ability to raise \'PropertyChanged\' event without explicit specifying the name of changed property. I would like to do something like this:

8条回答
  •  时光说笑
    2020-11-29 01:10

    In the following example you have to pass 3 values (backing field, new value, property as lambda) but there are no magic strings and property changed event is only raised when it truly isn't equal.

    class Sample : INotifyPropertyChanged
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { this.SetProperty(ref _name, value, () => this.Name); }
        }
    
    
        protected void SetProperty(ref T backingField, T newValue, Expression> propertyExpression)
        {
            if (backingField == null && newValue == null)
            {
                return;
            }
    
            if (backingField == null || !backingField.Equals(newValue))
            {
                backingField = newValue;
                this.OnPropertyChanged(propertyExpression);
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(Expression> propertyExpression)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.GetPropertyName()));
            }
        }
    
    }
    

    And the following code contains extension methods to get a property name from a lambda expression.

    public static class Extensions
    {
        public static string GetPropertyName(this Expression> propertyExpression)
        {
            return propertyExpression.Body.GetMemberExpression().GetPropertyName();
        }
    
        public static string GetPropertyName(this MemberExpression memberExpression)
        {
            if (memberExpression == null)
            {
                return null;
            }
    
            if (memberExpression.Member.MemberType != MemberTypes.Property)
            {
                return null;
            }
    
            var child = memberExpression.Member.Name;
            var parent = GetPropertyName(memberExpression.Expression.GetMemberExpression());
    
            if (parent == null)
            {
                return child;
            }
            else
            {
                return parent + "." + child;
            }
        }
    
        public static MemberExpression GetMemberExpression(this Expression expression)
        {
            var memberExpression = expression as MemberExpression;
    
            if (memberExpression != null)
            {
                return memberExpression;
            }
    
            var unaryExpression = expression as UnaryExpression;
    
    
            if (unaryExpression != null)
            {
                memberExpression = (MemberExpression)unaryExpression.Operand;
    
                if (memberExpression != null)
                {
                    return memberExpression;
                }
    
            }
            return null;
        }
    
        public static void ShouldEqual(this T actual, T expected, string name)
        {
            if (!Object.Equals(actual, expected))
            {
                throw new Exception(String.Format("{0}: Expected <{1}> Actual <{2}>.", name, expected, actual));
            }
        }
    
    }
    

    Finally some test code:

    class q3191536
    {
        public static void Test()
        {
            var sample = new Sample();
            var propertyChanged = 0;
    
            sample.PropertyChanged += 
                new PropertyChangedEventHandler((sender, e) => 
                    {
                        if (e.PropertyName == "Name")
                        {
                            propertyChanged += 1;
                        }
                    }
                );
    
            sample.Name = "Budda";
    
            sample.Name.ShouldEqual("Budda", "sample.Name");
            propertyChanged.ShouldEqual(1, "propertyChanged");
    
            sample.Name = "Tim";
            sample.Name.ShouldEqual("Tim", sample.Name);
            propertyChanged.ShouldEqual(2, "propertyChanged");
    
            sample.Name = "Tim";
            sample.Name.ShouldEqual("Tim", sample.Name);
            propertyChanged.ShouldEqual(2, "propertyChanged");
        }
    }
    

提交回复
热议问题