zoukankan      html  css  js  c++  java
  • 如何优雅的实现INotifyPropertyChanged接口

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

        

     1 class NotifyObject : INotifyPropertyChanged
     2     {
     3         private int number;
     4         public int Number
     5         {
     6             get { return number; }
     7             set { number = value; OnPropertyChanged("Number"); }
     8         }
     9 
    10         private string text;
    11         public string Text
    12         {
    13             get { return text; }
    14             set { text = value; OnPropertyChanged("Text"); }
    15         }
    16 
    17         public event PropertyChangedEventHandler PropertyChanged;
    18         protected void OnPropertyChanged(string propertyName = "")
    19         {
    20             PropertyChangedEventHandler handler = PropertyChanged;
    21             if (handler != null)
    22             {
    23                 handler(this, new PropertyChangedEventArgs(propertyName));
    24             }
    25         }
    26     }

    这种写法的两个问题是

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

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

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

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

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

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

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


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

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

    ]
      public class Person
      {

        public string GivenNames { get; set; }
        public string FamilyName { get; set; }

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

    编译后生成的代码如下:

     1 public class Person : INotifyPropertyChanged
     2 {
     3     public event PropertyChangedEventHandler PropertyChanged;
     4 
     5     string givenNames;
     6     public string GivenNames
     7     {
     8         get { return givenNames; }
     9         set
    10         {
    11             if (value != givenNames)
    12             {
    13                 givenNames = value;
    14                 OnPropertyChanged("GivenNames");
    15                 OnPropertyChanged("FullName");
    16             }
    17         }
    18     }
    19 
    20     string familyName;
    21     public string FamilyName
    22     {
    23         get { return familyName; }
    24         set 
    25         {
    26             if (value != familyName)
    27             {
    28                 familyName = value;
    29                 OnPropertyChanged("FamilyName");
    30                 OnPropertyChanged("FullName");
    31             }
    32         }
    33     }
    34 
    35     public string FullName
    36     {
    37         get
    38         {
    39             return string.Format("{0} {1}", GivenNames, FamilyName);
    40         }
    41     }
    42 
    43     public virtual void OnPropertyChanged(string propertyName)
    44     {
    45         var propertyChanged = PropertyChanged;
    46         if (propertyChanged != null)
    47         {
    48             propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    49         }
    50     }
    51 }

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

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

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

  • 相关阅读:
    NOI2018 退役记
    APIO2018 被屠记
    CTSC2018 被屠记
    SNOI2018 退役记
    O(1) long long a*b%p
    prufer编码
    杜教筛
    GCC卡常
    NOIP2017滚粗记
    UVA 10763 Foreign Exchange
  • 原文地址:https://www.cnblogs.com/yanglang/p/9935065.html
Copyright © 2011-2022 走看看