你的位置:首页 > ASP.net教程

[ASP.net教程]WPF学习07:MVVM 预备知识之数据绑定


    MVVM是一种模式,而WPF的数据绑定机制是一种WPF内建的功能集,两者是不相关的。

    但是,借助WPF各种内建功能集,如数据绑定、命令、数据模板,我们可以高效的在WPF上实现MVVM。因此,我们需要对各种MVVM相关的WPF内建功能集进行了解,才能在扎实的基础上对MVVM进行学习与实践。

    本文是WPF学习03:Element Binding的后续,将说明实现数据绑定的三个重点:DataContext INotifyPropertyChanged IValueConverter

 

MVVM简介

    MVVM将User Interface切成了3个部分,View、Model、View Model.

    三个部分区分如下:

    View:界面代码,并完成数据可视化。

    Model:一系列我们与业务层交互的类。

    View Model:1.将Model中需要显示的部分,转化为对View友好的数据。    2.管理View与View之间的交互。  

   image

    依赖关系如上图所示,V依赖于VM,反之不应该成立,VM依赖于M,反之亦不应成立。

    在完成了对数据绑定、命令、数据模板的理解后,我们再重新回来解释MVVM。


 

DataContext

    在WPF学习03:Element Binding中,我们只研究了如何在控件间实现数据绑定,在不指定ElementName时,Binding会在Source与RelativeSource也没有设置的情况下,一级一级的寻找DataContext,直到找到。

    例子:

    image

<StackPanel HorizontalAlignment="Center" TextBlock.Foreground="#019AFF" DataContext="{x:Static Colors.White}">  <!--指定Path,绑定对象的某个属性-->  <TextBlock Text="{Binding Path=R}"></TextBlock>  <TextBlock Text="{Binding Path=G}"></TextBlock>  <TextBlock Text="{Binding Path=B}"></TextBlock>  <!--不指定Path,绑定整个对象-->  <TextBlock Text="{Binding}"></TextBlock></StackPanel>

     比较常用的情况下,我们将DataContext设置在最顶层元素,一般情况下为Window。

     我们可以在后台代码中配置DataContext:

public class Person{  private Int32 _age;      public Int32 Age   {    get { return _age; }    set { _age = value; }  }  private String _name;  public String Name  {    get { return _name; }    set { _name = value; }  }}private void Window_Loaded(object sender, RoutedEventArgs e){  person = new Person() { Name = "Kenny", Age = 30 };  this.DataContext = person;}private void Button_Click(object sender, RoutedEventArgs e){  person.Name = "John Locke";  person.Age = 40;}

    XAML做的改动:

<StackPanel HorizontalAlignment="Center" TextBlock.Foreground="#019AFF">  <TextBlock Text="{Binding Path=Name}"></TextBlock>  <TextBlock Text="{Binding Path=Age}"></TextBlock>  <Button Click="Button_Click">Click me</Button></StackPanel>

    效果如下:

    image

     我们可以看到的确显示了期望值,但是如果点击按键的话,是看不到任何变化的,接下来即解释原因与解决方法。


 

INotifyPropertyChanged

    WPF内建的数据绑定机制中,Dependency Property不需额外做任何配置,即可在一般情况下建立数据绑定关系。WPF自建控件的各类属性都是依赖属性经传统的.Net属性包装而成。

    如果我们希望将数据绑定的源设为我们自己定义的对象的属性,且该属性不为依赖属性,那么就只有靠实现INotifyPropertyChanged接口,并在相应的属性改变时调用PropertyChanged事件以通知目标元素。

    我们将之前的后台代码做如下的改动:

public class Person : INotifyPropertyChanged{  public event PropertyChangedEventHandler PropertyChanged;
  private Int32 _age;    public Int32 Age   {    get { return _age; }    set {       _age = value;      if (PropertyChanged != null)        PropertyChanged.Invoke(this,new PropertyChangedEventArgs("Age"));    }  }  private String _name;  public String Name  {    get { return _name; }    set {      _name = value;      if (PropertyChanged != null)        PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));    }  }}

    效果如下:

    image

   


 

IValueConverter

    某些特殊的时候,源属性与目标属性是无法连接,需要进行转换,这时,就需要用到ValueConverter.直接给个例子:

    数据绑定实现根据年龄不同,文字显示同颜色,效果:

    imageimage

    XAML代码:

<TextBlock Text="{Binding Path=Name}"></TextBlock><TextBlock Name="AgeTextBlock" Text="{Binding Path=Age}"><TextBlock.Foreground>    <Binding Path="Age">      <Binding.Converter>        <local:TextBlockColorValueConverter></local:TextBlockColorValueConverter>      </Binding.Converter>    </Binding></TextBlock.Foreground></TextBlock>

    后台代码:
[ValueConversion(typeof(Boolean), typeof(Int32))]public class TextBlockColorValueConverter : IValueConverter{  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  {    if ((int)value < 18)      return new SolidColorBrush(Colors.Violet);    else      return new SolidColorBrush(Colors.Red);  }  //这里用不上数据从目标返回源,故返回null  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  {    return null;  }}


 

数据绑定的后台代码实现

     之前的数据绑定都是用XAML实现的,在此给出后台代码实现数据绑定的方法,实现刚才的例子:

     首先给两个控件标个Name,并去掉之前的所有绑定相关代码:

<TextBlock Name="NameTextBlock"></TextBlock><TextBlock Name="AgeTextBlock"></TextBlock>

      后台代码:

var bind = new Binding("Name"){  Source = person,};NameTextBlock.SetBinding(TextBlock.TextProperty, bind);bind = new Binding("Age"){  Source = person,};AgeTextBlock.SetBinding(TextBlock.TextProperty, bind);bind = new Binding("Age"){  Source = person,  Converter = new TextBlockColorValueConverter()};AgeTextBlock.SetBinding(TextBlock.ForegroundProperty, bind);

    效果与之前一致。