博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何优雅的实现INotifyPropertyChanged接口
阅读量:5241 次
发布时间:2019-06-14

本文共 2994 字,大约阅读时间需要 9 分钟。

原文:

INotifyPropertyChanged接口在WPF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更。标准写法如下:

    class NotifyObject : INotifyPropertyChanged

    {
        private int number;
        public int Number
        {
            get { return number; }
            set { number = value; OnPropertyChanged(
"Number"); }
        }
        private string text;
        public string Text
        {
            get { return text; }
            set { text = value; OnPropertyChanged(
"Text"); }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(thisnew PropertyChangedEventArgs(propertyName));
            }
        }
    }

这种写法的两个问题是

  1. 对属性名使用了字符串硬编码,容易写错,也不方便重构
  2. 冗余代码,如果属性较多的时候写得想吐

 我在博客文章中介绍了通过Caller Information解决属性名称字符串硬编码的问题。但是仍然不能解决冗余代码的问题。对于第二个问题,往往是通过AOP的方式实现,一般的实现方式有两种:

  1. 通过代理对象封装
  2. 通过编译期间代码注入的方式实现

我增在项目中使用过DynamicObject封装来实现过,主要原理是用实现一个PocoNotifyWrapper的DynamicObject类,托管其属性的读写动作,并附加IntofyPropertyChanged接口实现。

这种方式是动态的AOP了,是一个通用的方式,并且扩展性比较器,可以通过继承PocoNotifyWrapper来实现多态。用它做ViewMode层还是比较方便。

不过一个不大好的地方是DynamicObject是丢失了属性类型信息的,有时绑定时会出错(如将一个TextBox的Text绑定到一个封装后的Int类型对象时会不进行自动类型转换)。要解决它还需要实现一些其它的接口,实现起来还是有些复杂的,并且项目进度比较紧张,没有太多时间来完善它。

另外一种方式是通过编译期间代码注入方式来实现:

最开始见的是PostSharp的一个实现: 。不过PostSharp是收费的,后来也逐渐由了许多其它的免费的解决方案。本文这里介绍的是一个开源的解决方案:。

使用它非常简单,首先通过Nuget安装库:PM> Install-Package PropertyChanged.Fody。然后在需要实现属性通知的类上加一个[ImplementPropertyChanged]即可:

  [ImplementPropertyChanged]

  public class Person
  {

    public string GivenNames { get; set; }

    public string FamilyName { get; set; }

    public string FullName => string.Format("{0} {1}", GivenNames, FamilyName);

  }

 

编译后生成的代码如下:

public class Person : INotifyPropertyChanged{    public event PropertyChangedEventHandler PropertyChanged;    string givenNames;    public string GivenNames    {        get { return givenNames; }        set        {            if (value != givenNames)            {                givenNames = value;                OnPropertyChanged("GivenNames");                OnPropertyChanged("FullName");            }        }    }    string familyName;    public string FamilyName    {        get { return familyName; }        set         {            if (value != familyName)            {                familyName = value;                OnPropertyChanged("FamilyName");                OnPropertyChanged("FullName");            }        }    }    public string FullName    {        get        {            return string.Format("{0} {1}", GivenNames, FamilyName);        }    }    public virtual void OnPropertyChanged(string propertyName)    {        var propertyChanged = PropertyChanged;        if (propertyChanged != null)        {            propertyChanged(this, new PropertyChangedEventArgs(propertyName));        }    }}
View Code

基本上对代码没有注入,不需要安装插件,也不影响调试,实现非常简单,非常方便。

需要注意的是,如果实现了INotifyPropertyChanged接口,即使没有[ImplementPropertyChanged]标记,默认也会注入。另外,如果要实现更多的控制,可以参看如下链接:

除此之外,还有许多关于实现的INotifyPropertyChanged文章,感兴趣的朋友可以看一下:

posted on
2019-01-10 13:24 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10249441.html

你可能感兴趣的文章
IOS解析XML
查看>>
Python3多线程爬取meizitu的图片
查看>>
树状数组及其他特别简单的扩展
查看>>
zookeeper适用场景:分布式锁实现
查看>>
110104_LC-Display(液晶显示屏)
查看>>
javascript全局变量
查看>>
全连接神经网络(DNN)
查看>>
httpd_Vhosts文件的配置
查看>>
php学习笔记
查看>>
28 hashlib 模块 logging 模块 和 configparser模块 functools模块的偏函数partial
查看>>
普通求素数和线性筛素数
查看>>
React Router 4.0 基本使用
查看>>
作业完成2
查看>>
PHP截取中英文混合字符
查看>>
HTA - OnKeyDown
查看>>
【洛谷P1816 忠诚】线段树
查看>>
CDN 学习笔记
查看>>
电子眼抓拍大解密
查看>>
Linux系统下 /etc/shadow 档案结构
查看>>
多线程---线程间的通信
查看>>