MVVM写一个健壮的INotifiyPropertyChanged基类

本文介绍了一种简化MVVM模式中INotifyPropertyChanged接口实现的方法。通过使用泛型、扩展方法和LINQ等技术,避免了硬编码错误,并极大地减少了代码量。

当我们用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.Bodyis MemberExpression)
            {
                _pName = (exp.Body as MemberExpression).Member.Name;
            }
            else if(exp.Bodyis UnaryExpression)
            {
                _pName = ((exp.Body as UnaryExpression).Operandas 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.后就能出现我们要的属性




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值