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.后就能出现我们要的属性

 本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/3169864.html,如需转载请自行联系原作者

相关文章
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
925 1
|
设计模式 前端开发 C#
WPF 项目中 MVVM模式 的简单例子说明
本文通过WPF项目中的加法操作示例,讲解了MVVM模式的结构和实现方法,包括数据模型、视图、视图模型的创建和数据绑定,以及命令的实现和事件通知机制。
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
469 0
|
前端开发 开发者 C#
WPF开发者必读:MVVM模式实战,轻松实现现代桌面应用架构,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离应用程序的逻辑和界面,提高了代码的可维护性和可扩展性。本文介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定和逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种方式,开发者可以构建更加高效和可扩展的桌面应用程序。
863 0
|
设计模式 前端开发 C#
WPF/C#:理解与实现WPF中的MVVM模式
WPF/C#:理解与实现WPF中的MVVM模式
1440 0
|
前端开发 编译器 C#
【WPF】聊聊WPF中INotifyPropertyChanged [TOC]
【WPF】聊聊WPF中INotifyPropertyChanged [TOC]
282 0
|
前端开发 C# 图形学
【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入
前言:在C/S架构上,WPF无疑已经是“桌面一霸”了。在.NET生态环境中,很多小伙伴还在使用Winform开发C/S架构的桌面应用。但是WPF也有很多年的历史了,并且基于MVVM的开发模式,受到了很多开发者的喜爱。
1191 0
【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入
|
设计模式 开发框架 前端开发
深入理解WPF中MVVM的设计思想
近些年来,随着WPF在生产,制造,工业控制等领域应用越来越广发,很多企业对WPF开发的需求也逐渐增多,使得很多人看到潜在机会,不断从Web,WinForm开发转向了WPF开发,但是WPF开发也有很多新的概念及设计思想,如:数据驱动,数据绑定,依赖属性,命令,控件模板,数据模板,MVVM等,与传统WinForm,ASP.NET WebForm开发,有很大的差异,今天就以一个简单的小例子,简述WPF开发中MVVM设计思想及应用。
350 0
|
前端开发
WPF-Binding问题-MVVM中IsChecked属性CommandParameter转换值类型空异常
WPF-Binding问题-MVVM中IsChecked属性CommandParameter转换值类型空异常
321 0
|
前端开发 算法 JavaScript
走进WPF之MVVM完整案例
走进WPF之MVVM完整案例
667 0