• WPF MVVM 写一个健壮的INotifyPropertyChanged基类


    当我们用MVVM的时候要实现INotifyPropertyChanged,如果你是基于.net4.5以下的framework(.net4.5已有新特性我这里就不说了)

    你很可能会这么写

     public class MyModel : INotifyPropertyChanged
        {
            private string _Name;
            public string Name
            {
                get
                {
                    return _Name;
                }
                set
                {
                    _Name = value;
                    OnPropertyChanged("Name");//会造成硬编码错误
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    

    这样的写法很可能会造成硬编码错误

    你是不是有点烦每次要写一个字段还要写一个属性还要加上OnPropertyChanged,有没好一点的方法让我们少写

    代码呢,能是能用现有的技术实现我们想要的像下面这样

        public class MyModel : PropertyNotifyObject
        {
            public string Name
            {
                get
                {
                    return this.GetValue(x => x.Name);
                }
                set
                {
                    this.SetValue(x => x.Name, value);
                }
            }
        }
    

    哇!这么写看着好简单呀,而且还能有效避免硬编码对你带来的问题。

    写一个x.就能出现你要的属性

    对!这样你就能省下更多的时间去写加的代码了,

    先说明一下用到的技术没有新的只是只用到了泛型扩展方法和一点linq,要怎么实现呢?来让我们一步一步的实现

    我们先写一个公共类方法

    public class MyCommMetoh
        {
            //得到属性的名称
            public static string GetPropertyName<T, U>(Expression<Func<T, U>> exp)
            {
                string _pName = "";
                if (exp.Body is MemberExpression)
                {
                    _pName = (exp.Body as MemberExpression).Member.Name;
                }
                else if(exp.Body is UnaryExpression)
                {
                    _pName = ((exp.Body as UnaryExpression).Operand as MemberExpression).Member.Name; 
                }
                return _pName;
            }
        }
    

    这个GetPropertyName方法是根据一个Lambda表达式得到属性的名称

    像这上面 this.GetValue(x => x.Name) ,这个方法就是用x => x.Name做为参数得到Name这个名字

    这样可以有效的防止硬编码错误

    实现一下INotifyPropertyChanged接口

        public class NotifyPropertyBase : INotifyPropertyChanged
        {
            #region INotifyPropertyChanged
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion
        }
        public static class NotifyPropertyBaseEx
        {
            public void OnPropertyChanged<T, U>(this T npb, Expression<Func<T, U>> exp) where T : NotifyPropertyBase,new()
            {
                string _PropertyName = MyCommMetoh.GetPropertyName(exp);
                npb.OnPropertyChanged(_PropertyName);
            }
        }
    

    上边的类我想你并不陌生吧,下这那个是个扩展类,如果你不太明白那就先回去看一下基础吧

    是利用扩展根据lambda用上边我们写的公共类方法得到属性的名称,这也是为防止硬编码而做的工作

    下面才是我们真正的基类PropertyNotifyObject,这个类是我们存放数据值,修改和查询值的

    看一下我是怎么写的

    public class PropertyNotifyObject : NotifyPropertyBase,IDisposable
        {
            public PropertyNotifyObject() { }
    
            Dictionary<object, object> _ValueDictionary = new Dictionary<object, object>();
    
            #region 根据属性名得到属性值
            public T GetPropertyValue<T>(string propertyName)
            {
                if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("invalid " + propertyName);
                object _propertyValue;
                if(!_ValueDictionary.TryGetValue(propertyName,out _propertyValue))
                {
                    _propertyValue = default(T);
                    _ValueDictionary.Add(propertyName, _propertyValue);
                }
                return (T)_propertyValue;
            }
            #endregion
    
            public void SetPropertyValue<T>(string propertyName, T value)
            {
                if (!_ValueDictionary.ContainsKey(propertyName) || _ValueDictionary[propertyName] != (object)value)
                {
                    _ValueDictionary[propertyName] = value;
                    OnPropertyChanged(propertyName);
                }
            }
    
            #region Dispose
            public void Dispose()
            {
                DoDispose();
            }
            ~PropertyNotifyObject()
            {
                DoDispose();
            }
            void DoDispose()
            {
                if (_ValueDictionary != null)
                    _ValueDictionary.Clear();
            }
            #endregion
        }
        public static class PropertyNotifyObjectEx
        {
            public static U GetValue<T, U>(this T t, Expression<Func<T, U>> exp) where T : PropertyNotifyObject
            {
                string _pN = MyCommMetoh.GetPropertyName(exp);
                return t.GetPropertyValue<U>(_pN);
            }
    
            public static void SetValue<T, U>(this T t, Expression<Func<T, U>> exp, U value) where T : PropertyNotifyObject
            {
                string _pN = MyCommMetoh.GetPropertyName(exp);
                t.SetPropertyValue<U>(_pN, value);
            }
        }
    

    这是用一个字典把所有的存放了起来,看下面有一个扩展这个扩展就能让我们实现

            public string Name
            {
                get
                {
                    return this.GetValue(x => Name);
                }
                set
                {
                    this.SetValue(x => x.Name, value);
                }
            }
    

    的x => x.Name。这样就能让我们写完x.后就能出现我们要的属性

      

  • 相关阅读:
    org.hibernate.MappingException: duplicate import异常
    java web项目导入问题
    android.os.NetworkOnMainThreadException解决
    Eclipse无法识别小米2S手机
    ANDROID模拟器访问本地WEB应用
    【UE4】二十四、UE4内部版本引擎和官方版本引擎版本保持兼容的方法
    【UE4】二十三、UE4笔试面试题
    如何设置文件审计软件FileAudit的浏览选项
    PHP
    PHP
  • 原文地址:https://www.cnblogs.com/li-peng/p/3169864.html
Copyright © 2020-2023  润新知