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 Dog
12     {
13         get { return m_Dog; }
14         set { m_Dog = value; RaisePropertyChanged(); }
15     }
16 
17     private string m_Tiger;
18     public string Tiger
19     {
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 MyAnimal
10     {
11         get { return m_MyAnimal; }
12         set { m_MyAnimal = value; RaisePropertyChanged("MyAnimal"); }
13     }
14 
15     public ICommand OKCommand
16     {
17         get
18         {
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>


运行效果。

原文地址:https://www.cnblogs.com/yuefei/p/3799430.html