[WPF/Silverlight]让INotifyPropertyChanged的实现更优雅一些

简介:

我想大部分的WPF和SL开发者都应该对INotifyPropertyChanged这个接口再熟悉不过了。当我们向UI传递属性变化的通知并更新客户端UI时就必须应用到它。(这里插一句,当一个集合中的项改变时我们则需要使用ObservableCollection<T>泛型集合)

假设我们有一个叫做MenuButtonModel的类,其中一个属性为HasFocus,那么通常情况下我们会这样实现INotifyPropertyChanged接口

【补充】 INotifyPropertyChanged.PropertyChanged事件,它什么时候为空不为空??

控件绑定数据源时,控件会自动订阅实现了INotifyPropertyChanged接口的对象的PropertyChanged事件。有人订阅了它就不再是null了。
如果它谁都没绑定,那肯定是null了。一般Binding之后就不空了.也就是说,event 用 += 操作之后, 他就不为null了,因为控件绑定数据源时会自动订阅实现了INotifyPropertyChanged接口的对象的PropertyChanged事件。
假如你不是绑定到控件上,而是另一个(些)对象手动绑定这个对象的PropertyChanged事件,那么哪个时刻开始觉得没必要再监视这个对象的属性的变化,用-=操作取消了订阅,那很显然,PropertyChanged又会变成null.  

【补充2】用不用PropertyChanged有什么区别?(不是很明白,请高手指点!)    

  msdn 是這樣說的:

‧如果不呼叫 PropertyChanged,就無法把控制項執行個體記號為需要儲存的。因此它們將不會收到 WriteProperties 事件,使用控制項的開發人員將遺失在設計階段設定的任何屬性值。
‧因為屬性值可能顯示在多個地方,因此當屬性值發生改變時必須通知開發環境,以便使它能夠同步顯示「屬性」視窗、「屬性頁」對話方塊等位置上的屬性值。
另外建議 initprop 裡使用 m_BackColor = Ambient.BackColor,還有 backcolor 的 get/let 型態使用 ole_color 而不是 long。最後建議在「工具-程式屬性-backcolor-進階-程序識別碼」裡選擇 backcolor。      

 
public  class  MenuButtonModel : INotifyPropertyChanged
   {
       public  event  PropertyChangedEventHandler PropertyChanged;
 
       private  bool ? _hasFocus;
       public  bool ? HasFocus
       {
           get  { return  _hasFocus; }
           set
           {
               _hasFocus = value;
               if  (PropertyChanged != null )
               {
                   PropertyChanged( this , new  PropertyChangedEventArgs( "HasFocus" ))
               }
           }
       }
   }
 
 
   //当这个类的属性比较多的时候(如多了一个IconPath属性),我们又将NotifyPropertyChanged独立出来,如:
   public  class  MenuButtonModel : INotifyPropertyChanged
   {
       public  event  PropertyChangedEventHandler PropertyChanged;
       public  void  NotifyPropertyChanged( string  propertyName)
       {
           if  (PropertyChanged != null )
           {
               PropertyChanged( this , new  PropertyChangedEventArgs(propertyName));
           }
       }
 
       private  bool ? _hasFocus;
       public  bool ? HasFocus
       {
           get  { return  _hasFocus; }
           set
           {
               _hasFocus = value;
               NotifyPropertyChanged( "HasFocus" );
           }
       }
 
       private  string  _iconPath;
       public  string  IconPath
       {
           get  { return  _iconPath; }
           set
           {
               _iconPath = value;
               NotifyPropertyChanged( "IconPath" );
           }
       }
   }
   //当我们的类越来越多时,写这样的代码又显得有些疲于奔命。于是乎大家想到了为这些类建立一个共同的基类。所有该基类的派生类自然都实现了IPropertyChanged接口。如下例中的PropertyChangedBase类:
   public  class  PropertyChangedBase : INotifyPropertyChanged
   {
       public  event  PropertyChangedEventHandler PropertyChanged;
 
       public  void  NotifyPropertyChanged( string  propertyName)
       {
           if  ( this .PropertyChanged != null )
           {
               this .PropertyChanged( this , new  PropertyChangedEventArgs(propertyName));
           }
       }
   }
   //然后我们改动MenuButton类,使其继承PropertyChangedBase:
   public  class  MenuButtonModel : PropertyChangedBase
   {
       private  bool ? _hasFocus;
       public  bool ? HasFocus
       {
           get  { return  _hasFocus; }
           set
           {
               _hasFocus = value;
               NotifyPropertyChanged( "HasFocus" );
           }
       }
 
       private  string  _iconPath;
       public  string  IconPath
       {
           get  { return  _iconPath; }
           set
           {
               _iconPath = value;
               NotifyPropertyChanged( "IconPath" );
           }
       }
   //现在看起来好多了。不过做为有洁癖的程序员,这样的方法显然不会满足俺们的要求,因为我们仍然需要硬编码一个Name(如:IconPath),这很不爽。即使写错了,编译器也不会发现这个潜在的错误。从成千上万个类中寻找一个硬编码问题会让人抓狂。老赵说过要尽量使用强类型,这绝对是至理名言。。。,那么表达式树正式登场!我们需要稍微的改动一下PropertyChangedBase类(这里注意需要using System.Linq.Expressions):
   public  class  PropertyChangedBase : INotifyPropertyChanged
   {
       public  event  PropertyChangedEventHandler PropertyChanged;
 
       public  void  NotifyPropertyChanged<T>(Expression<Func<T>> propertyName)
       {
           if  ( this .PropertyChanged != null )
           {
               var  memberExpression = propertyName.Body as  MemberExpression;
               if  (memberExpression != null )
               {
                   this .PropertyChanged( this ,
                     new  PropertyChangedEventArgs(memberExpression.Member.Name));
               }
           }
       }
   }
 
 
   //经过如上改动,我们就可以在派生类中使用优雅的强类型啦~,如下:
   public  class  MenuButtonModel : PropertyChangedBase
   {
       private  bool ? _hasFocus;
       public  bool ? HasFocus
       {
           get  { return  _hasFocus; }
           set
           {
               _hasFocus = value;
               NotifyPropertyChanged< bool ?>(() => this .HasFocus);
           }
       }
 
       private  string  _iconPath;
       public  string  IconPath
       {
           get  { return  _iconPath; }
           set
           {
               _iconPath = value;
               NotifyPropertyChanged< string >(() => this .IconPath);
           }
       }
   }
   //看起来还不错。不过<bool?>,<string>依然不是很爽,如果可以this.NotifyPropertyChanged( p => p.HasFocus),那多帅啊。要实现这个目的,我们需要使用扩展方法。搞一个静态类出来,如下:
   public  static  class  PropertyChangedBaseEx
   {
       public  static  void  NotifyPropertyChanged<T, TProperty>( this  T propertyChangedBase,
         Expression<Func<T, TProperty>> expression) where  T : PropertyChangedBase
       {
           var  memberExpression = expression.Body as  MemberExpression;
           if  (memberExpression != null )
           {
               string  propertyName = memberExpression.Member.Name;
               propertyChangedBase.NotifyPropertyChanged(propertyName);
           }
           else
               throw  new  NotImplementedException();
       }
   }
   //然后我们就可以在类中用优雅的语法实现PropertyChanged了。
 
   //全部代码如下:
 
   //MenuButton.cs
   public  class  MenuButtonModel : PropertyChangedBase
   {
       private  bool ? _hasFocus;
       public  bool ? HasFocus
       {
           get  { return  _hasFocus; }
           set
           {
               _hasFocus = value;
               this .NotifyPropertyChanged(p => p.HasFocus);
           }
       }
 
       private  string  _iconPath;
       public  string  IconPath
       {
           get  { return  _iconPath; }
           set
           {
               _iconPath = value;
               this .NotifyPropertyChanged(p => p.IconPath);
           }
       }
   }
   PropertyChangedBase.cs以及PropertyChangedBaseEx.cs
   public  class  PropertyChangedBase : INotifyPropertyChanged
   {
       public  event  PropertyChangedEventHandler PropertyChanged;
 
       public  void  NotifyPropertyChanged( string  propertyName)
       {
           if  ( this .PropertyChanged != null )
           {
               this .PropertyChanged( this , new  PropertyChangedEventArgs(propertyName));
           }
       }
   }
 
   public  static  class  PropertyChangedBaseEx
   {
       public  static  void  NotifyPropertyChanged<T, TProperty>( this  T propertyChangedBase,
         Expression<Func<T, TProperty>> expression) where  T : PropertyChangedBase
       {
           var  memberExpression = expression.Body as  MemberExpression;
           if  (memberExpression != null )
           {
               string  propertyName = memberExpression.Member.Name;
               propertyChangedBase.NotifyPropertyChanged(propertyName);
           }
           else
               throw  new  NotImplementedException();
       }
   }

  

需要注意的是,因为是扩展方法,所有this关键字不能省略。

ok,就到这里,have fun~



本文转自Work Hard Work Smart博客园博客,原文链接:http://www.cnblogs.com/linlf03/archive/2011/08/30/2159614.html,如需转载请自行联系原作者

目录
相关文章
|
C#
WPF 界面实现多语言支持 中英文切换 动态加载资源字典
原文:WPF 界面实现多语言支持 中英文切换 动态加载资源字典 1、使用资源字典,首先新建两个字典文件en-us.xaml、zh-cn.xaml。定义中英文的字符串在这里面【注意:添加xmlns:s="clr-namespace:System;assembly=mscorlib】 zh-cn.
3184 0
|
C# 数据可视化 开发工具
WPF实现选项卡效果(1)——使用AvalonDock
原文:WPF实现选项卡效果(1)——使用AvalonDock 简介   公司最近一个项目,软件采用WPF开发,需要实现类似于VS的选项卡(或者是浏览器的选项卡)效果。
2258 0
|
5月前
|
前端开发 编译器 C#
【WPF】聊聊WPF中INotifyPropertyChanged [TOC]
【WPF】聊聊WPF中INotifyPropertyChanged [TOC]
42 0
WPF学习—INotifyPropertyChanged Interface
WPF学习—INotifyPropertyChanged Interface
WPF学习—INotifyPropertyChanged Interface
|
IDE C# 开发工具
WPF钟表效果实现
中WPF中的RotateTransform实现UI元素的旋转,并模拟钟表的秒针、分针和时针。
1196 0
WPF钟表效果实现
|
IDE 编译器 C#
WPF实现强大的动态公式计算
数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。本文就探讨一下如何在WPF中实现一种基于行字段的动态公式计算。
1066 0
WPF实现强大的动态公式计算
|
网络协议 C# 移动开发
C# WPF上位机实现和下位机TCP通讯
C# WPF上位机实现和下位机TCP通讯下位机使用北京大华程控电源DH1766-1,上位机使用WPF。实现了电压电流实时采集,曲线显示。上午在公司调试成功,手头没有程控电源,使用TCP服务端模拟。昨天写的TCP服务端正好排上用场。
2399 0
|
C#
WPF特效-实现3D足球效果
原文:WPF特效-实现3D足球效果 WPF 实现 3D足球效果,效果图如下:  每个面加载不同贴图。                                                          ...
915 0
|
算法 C# 容器
WPF特效-实现弧形旋转轮播图
原文:WPF特效-实现弧形旋转轮播图        项目遇到,琢磨并实现了循环算法,主要处理循环替换显示问题       (如:12张图组成一个圆弧,但总共有120张图需要呈现,如何在滑动中进行显示块的替换,并毫无卡顿)        处理的自己感觉比较满意,记录一下。
2150 0
|
C#
wpf采用Xps实现文档显示、套打功能
原文:wpf采用Xps实现文档显示、套打功能 近期的一个项目需对数据进行套打,用户要求现场不允许安装office、页面预览显示必须要与文档完全一致,xps文档来对数据进行处理。Wpf的DocumentView 控件可以直接将数据进行显示,xps也是一种开放式的文档,如果我们能够替换里面的标签就最终实现了我们想要的效果。
1793 0

热门文章

最新文章