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

  

WPF MVVM 写一个健壮的INotifyPropertyChanged基类的更多相关文章

  1. java 写一个JSON解析的工具类

    上面是一个标准的json的响应内容截图,第一个红圈”per_page”是一个json对象,我们可以根据”per_page”来找到对应值是3,而第二个红圈“data”是一个JSON数组,而不是对象,不能 ...

  2. 模仿.NET框架ArrayList写一个自己的动态数组类MyArrayList,揭示foreach实现原理

    通过.NET反编译工具可以查看到ArrayList内部的代码,发现ArrayList并非由链表实现,而是由一个不断扩容的数组对象组成. 下面模仿ArrayList写一个自己的MyArrayList. ...

  3. [WPF][Rubyer] 写一个自己的 UI 库 (二) - Icon

    前言 制作 WPF 的图标包,主要介绍从 iconfont 下载的图标包导入到 WPF 使用: 1. 添加文件 Ruyber 下添加 自定义控件(WPF) Icon.cs.类 IconType.cs. ...

  4. 用node.js给C#写一个数据表的实体类生成工具

    虽然微软提供了T4模板,但是我感觉非常难用.哪儿比得上直接用脚本来写模板来的爽. 因为要给一个老项目做周边的工具,需要连接到数据库. 我习惯性用EntityFrameworkCore来做,因为毕竟从出 ...

  5. 一个关于C#中基类与接口混合继承的疑问总结

    思路参照 http://www.cnblogs.com/allenlooplee/archive/2004/11/16/64553.html,对原文进行了简化和补充,感谢原作者. 问题很简单,如下所示 ...

  6. 写一个操作 .ini文件的类

    class IniHelp { private string iniPath; [DllImport("kernel32")] private static extern long ...

  7. 工作线程基类TaskSvc

    工作线程基类TaskSvc 前端时间用ACE写代码,发ACE_Task确实好用.不但能提供数量一定的线程,还能够让这些继承的线程函数自由访问子类的private和protected变量.此外,ACE_ ...

  8. WPF/MVVM 快速开始指南(译)(转)

    WPF/MVVM 快速开始指南(译) 本篇文章是Barry Lapthorn创作的,感觉写得很好,翻译一下,做个纪念.由于英文水平实在太烂,所以翻译有错或者译得不好的地方请多指正.另外由于原文是针对W ...

  9. 自己写一个java.lang.reflect.Proxy代理的实现

    前言 Java设计模式9:代理模式一文中,讲到了动态代理,动态代理里面用到了一个类就是java.lang.reflect.Proxy,这个类是根据代理内容为传入的接口生成代理用的.本文就自己写一个Pr ...

随机推荐

  1. SAM4E单片机之旅——14、LCD之SMC的配置

    在上个例子中,已经在ASF添加了ILI93xx模块,并做好了相关的声明.这次就做好SMC的配置,然后使用ASF提供的API在屏幕上打印出”Hello World!”字样. 一. 电路图 开发板的LCD ...

  2. PowerVault TL4000 Tape Library 告警:“Media Attention”

      Dell PowerVault TL4000 磁带库机的指示灯告警,从Web管理平台登录后,在菜单"Library Status"下发现如下告警信息:  Library Sta ...

  3. 一个关于group by和having子句的小例子

    表结构: 要求: 查询有多个员工的工资不低于2000的部门编号(就是说如果一个部门的员工大于2000的人数有两个或两个以上就查询出来) sql语句: select [DEPARTMENT_ID],co ...

  4. 修改Tomcat服务器的端口号

    关键技术: Connector子元素下的port是设置服务器端口,而connection Timeout则是服务器连接超时单位为毫秒. 操作过程: (1)采用记事本打开Tomcat安装目录下的conf ...

  5. js模板

    作用 适合用于定义模板(模板容器),不解析(渲染/执行). 为什么这样使用 在js里面,经常需要使用js往页面中插入html内容.比如这样: var number = 123; $('#d').app ...

  6. 【SQL 代码】Sql分页(自用)

    效果图: 下面是存储过程的创建,用的时候调用就行了 /****** Object: StoredProcedure [dbo].[spSqlPageByRownumber] Script Date: ...

  7. Python天猫淘宝评论爬虫

    说明 由于Github 打包的exe某些文件上传被.gitignore了,所以不提供windows二进制包 https://github.com/hunterhug/taobaocomment 一个抓 ...

  8. app:transformClassesWithJarMergingForDebug uplicate entry: android/support/v4/app/BackStackState$1.class

    .Execution failed for task ':app:transformClassesWithJarMergingForDebug'.> com.android.build.api. ...

  9. 在Centos5下安装GraphicsMagick

    安装GraphicsMagick的流水账: 安装参照的http://www.graphicsmagick.org/INSTALL-unix.html 解压 /home/milton/GraphicsM ...

  10. 导航 tab