首页 > 代码库 > xaml mvvm(2)之属性绑定

xaml mvvm(2)之属性绑定

通过微软INotifyPropertyChanged接口,可以实现对UI实时更新,不管是数据源或者目标对象,可以实现相互通知。

下面我们根据INotifyPropertyChanged编写一个扩展类。该类是基于C#5.0特性,这里我们介绍一下System.Runtime.CompilerServices命名空间下的CallerMemberName特性,当RaisePropertyChanged的属性名称参数为空,而通过编译器可以智能加上,可以通过反编译工具知晓,这点改进这点很人性化。注:如果开发版本framework 4.0,则需要安装KB2468871补丁或者更新framework 4.0以上版本。

为这个扩展类添加命名空间如下。

1 using System;2 using System.Collections.Generic;3 using System.ComponentModel;4 using System.Diagnostics;5 using System.Linq.Expressions;6 using System.Reflection;7 using System.Runtime.CompilerServices;
 1 public class ObservableObject : INotifyPropertyChanged 2 { 3     public event PropertyChangedEventHandler PropertyChanged; 4     protected PropertyChangedEventHandler PropertyChangedHandler 5     { 6         get 7         { 8             return this.PropertyChanged; 9         }10     }11     [Conditional("DEBUG"), DebuggerStepThrough]12     public void VerifyPropertyName(string propertyName)13     {14         Type type = base.GetType();15         if (!string.IsNullOrEmpty(propertyName) && type.GetTypeInfo().GetDeclaredProperty(propertyName) == null)16         {17             throw new ArgumentException("Property not found", propertyName);18         }19     }20     protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)21     {22         PropertyChangedEventHandler propertyChanged = this.PropertyChanged;23         if (propertyChanged != null)24         {25             propertyChanged(this, new PropertyChangedEventArgs(propertyName));26         }27     }28     protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)29     {30         PropertyChangedEventHandler propertyChanged = this.PropertyChanged;31         if (propertyChanged != null)32         {33             string propertyName = ObservableObject.GetPropertyName<T>(propertyExpression);34             propertyChanged(this, new PropertyChangedEventArgs(propertyName));35         }36     }37     protected static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)38     {39         if (propertyExpression == null)40         {41             throw new ArgumentNullException("propertyExpression");42         }43         MemberExpression memberExpression = propertyExpression.Body as MemberExpression;44         if (memberExpression == null)45         {46             throw new ArgumentException("Invalid argument", "propertyExpression");47         }48         PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;49         if (propertyInfo == null)50         {51             throw new ArgumentException("Argument is not a property", "propertyExpression");52         }53         return propertyInfo.Name;54     }55     protected bool Set<T>(Expression<Func<T>> propertyExpression, ref T field, T newValue)56     {57         if (EqualityComparer<T>.Default.Equals(field, newValue))58         {59             return false;60         }61         field = newValue;62         this.RaisePropertyChanged<T>(propertyExpression);63         return true;64     }65     protected bool Set<T>(string propertyName, ref T field, T newValue)66     {67         if (EqualityComparer<T>.Default.Equals(field, newValue))68         {69             return false;70         }71         field = newValue;72         this.RaisePropertyChanged(propertyName);73         return true;74     }75     protected bool Set<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)76     {77         return this.Set<T>(propertyName, ref field, newValue);78     }79 }

 

下面我们来继承这个类编写一个Animal类对象。在这里我们用到RaisePropertyChanged三种不同的实现方式,达到一样的绑定效果。

 1 public class Animal : ObservableObject 2 { 3     private string m_Cat; 4     public string Cat 5     { 6         get { return m_Cat; } 7         set { m_Cat = value; RaisePropertyChanged("Cat"); } 8     } 9 10     private string m_Dog;11     public string Dog12     {13         get { return m_Dog; }14         set { m_Dog = value; RaisePropertyChanged(); }15     }16 17     private string m_Tiger;18     public string Tiger19     {20         get { return m_Tiger; }21         set { m_Tiger = value; RaisePropertyChanged(() => this.Tiger); }22     }23 }


下面我们来建立model视图类。在该类中用的事件绑定和model对象实现,我们会在后续介绍。

 1 public class MainPageViewModel : Core.ViewModelBase 2 { 3     public MainPageViewModel() 4     { 5         MyAnimal = new Animal(); 6     } 7  8     private Animal m_MyAnimal; 9     public Animal MyAnimal10     {11         get { return m_MyAnimal; }12         set { m_MyAnimal = value; RaisePropertyChanged("MyAnimal"); }13     }14 15     public ICommand OKCommand16     {17         get18         {19             return new RelayCommand(() =>20             {21                 MyAnimal.Dog = "eating";22                 MyAnimal.Cat = "sleeping";23                 MyAnimal.Tiger = "hungry";24             });25         }26     }27 }


前台xaml。

 1 <Grid DataContext="{Binding Path=MainPageViewModel}"> 2     <StackPanel> 3         <StackPanel Orientation="Horizontal"> 4             <TextBlock FontSize="25" Text="cat is:" /> 5             <TextBlock FontSize="25" Text="{Binding MyAnimal.Cat}" /> 6         </StackPanel> 7         <StackPanel Orientation="Horizontal"> 8             <TextBlock FontSize="25" Text="dog is:" /> 9             <TextBlock FontSize="25" Text="{Binding MyAnimal.Dog}" />10         </StackPanel>11         <StackPanel Orientation="Horizontal">12             <TextBlock FontSize="25" Text="Tiger is:" />13             <TextBlock FontSize="25" Text="{Binding MyAnimal.Tiger}" />14         </StackPanel>15         <Button Width="60" Content="OK" Command="{Binding OKCommand}" />16     </StackPanel>17 </Grid>


运行效果。