• 小静   2014/8/21 12:50:00
  • Silverlight中INotifyPropertyChanged 接口在数据绑定中的使用
  • 关键字: Silverlight 数据绑定
  •   INotifyPropertyChanged是什么,它有什么作用?通过查阅MSDN我们知道,INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。

       当绑定数据源的某属性值改变时,它可以通知客户端,并进行界面数据更新.而我们不用写很多复杂的代码来更新界面数据,这样可以做到方法简洁而清晰,INotifyPropertyChanged确实是一个强大的接口。
      首先,我们需要了解如下有关Silverlight 2.0 数据绑定的术语:

    复制代码

      Binding 
    - 将绑定目标对象的属性与数据源联接起来
      Source 
    - 绑定的数据源
      Mode 
    - 绑定的数据流的方向 [System.Windows.Data.BindingMode枚举]
      BindingMode.OneTime 
    - 一次绑定。创建绑定时一次性地更新绑定目标对象的属性
      BindingMode.OneWay 
    - 单向绑定(默认值)。数据源的改变会自动通知到绑定目标对象的属性
      BindingMode.TwoWay 
    - 双向绑定。数据源或绑定目标对象的属性的值发生改变时会互相通知。显然,做数据验证的话一定要是双向绑定
      INotifyPropertyChanged 
    - 向客户端发出某一属性值已更改的通知
      IValueConverter 
    - 值转换接口,将一个类型的值转换为另一个类型的值。它提供了一种将自定义逻辑应用于绑定的方式
    复制代码

    接下来我们学习简单的数据绑定并了解INotifyPropertyChanged所发挥的作用。
       首先启动VS2008,新建Silverlight应用程序,程序名为MyINotifyPropertyChanged,系统自动为我们建立两个项目,一个是MyINotifyPropertyChanged,一个是MyINotifyPropertyChanged.Web。在MyINotifyPropertyChanged子项目下,我们添加了两类数据源:
       StudentNotify.cs :引入了INotifyPropertyChanged接口

     using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.ComponentModel;  //需要添加此命名空间

    namespace MyINotifyPropertyChanged
    {
        
    public class StudentNotify : INotifyPropertyChanged
        {
            
    private string NameValue;
            
    private int AgeValue;

            
    public string SName
            {
                
    get { return NameValue; }
                
    set
                {
                    NameValue 
    = value;
                    
    // Call NotifyPropertyChanged when the property is updated
                    NotifyPropertyChanged("SName");
                }
            }
            
    public int  SAge
            {
                
    get { return AgeValue; }
                
    set
                {
                    AgeValue 
    = value;
                    
    // Call NotifyPropertyChanged when the property is updated
                    NotifyPropertyChanged("SAge");
                }
            }


            
    // Declare the PropertyChanged event
            public event PropertyChangedEventHandler PropertyChanged;

            
    // NotifyPropertyChanged will raise the PropertyChanged event passing the
            
    // source property that is being updated.
            public void NotifyPropertyChanged(string propertyName)
            {
                
    if (PropertyChanged != null)
                {
                    PropertyChanged(
    thisnew PropertyChangedEventArgs(propertyName));
                }
            }

            
    public StudentNotify()
            {
            }
            
    public StudentNotify(string NameStr,int AgeInt)
            {
                SName 
    = NameStr;
                SAge 
    = AgeInt;
            }
        }
    }
     Student.cs       :没有引入INotifyPropertyChanged接口 

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace MyINotifyPropertyChanged
    {
        
    public class Student
        {
            
    public string SName { getset; }
            
    public int SAge { getset; }
        }
    }
     对于呈现界面我们设计了两大组基于不同Binding Mode值的TextBox
       第一组的TextBox其BindingMode值分别为:
       Default
       OneTime
       OneWay
       TwoWay
       第二组的TextBox其BindingMode值全部为:
       TwoWay
       此外,我们设计了一个ComboBox,用于选择我们将要对上述两组呈现界面进行数据绑定的不同数据源。


    因此,Page.xaml代码如下:

    <UserControl x:Class="MyINotifyPropertyChanged.Page"
        xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width
    ="400" Height="500">
        
    <Grid x:Name="LayoutRoot" Background="White">
            
    <Grid.RowDefinitions>
                
    <RowDefinition Height="200"></RowDefinition>
                
    <RowDefinition Height="20" ></RowDefinition>
                
    <RowDefinition Height="200" ></RowDefinition>
            
    </Grid.RowDefinitions>
            
    <Grid.ColumnDefinitions>
                
    <ColumnDefinition Width="200" />
                
    <ColumnDefinition Width="200" />
            
    </Grid.ColumnDefinitions>
            
    <StackPanel Grid.Row="0" Grid.Column="0" Background="Azure" Orientation="Vertical" Margin="20">
                
    <TextBlock x:Name="tbNameOne" Width="150" Text="姓名-default" TextAlignment="Center" FontSize="20" Foreground="Blue"  Margin="4" ></TextBlock>
                
    <TextBlock x:Name="tbAgeOne" Width="150" Text="年龄-OneTime" TextAlignment="Center" FontSize="20" Foreground="Blue"  Margin="4"></TextBlock>
                
    <TextBlock x:Name="tbNameTwo" Width="150" Text="姓名-OneWay" TextAlignment="Center" FontSize="20" Foreground="Brown"  Margin="4"></TextBlock>
                
    <TextBlock x:Name="tbAgeTwo" Width="150" Text="年龄-TwoWay" TextAlignment="Center" FontSize="20" Foreground="Brown"  Margin="4"></TextBlock>
            
    </StackPanel>    
            
            
    <StackPanel Grid.Row="0" Grid.Column="1" Background="Aqua"  Orientation="Vertical" Margin="20">
                
    <TextBox x:Name="txtNameOne" Text="{Binding SName}" Margin="6"></TextBox>
                
    <TextBox x:Name="txtAgeOne" Text="{Binding SAge,Mode=OneTime}" Margin="6"></TextBox>
                
    <TextBox x:Name="txtNameTwo" Text="{Binding SName,Mode=OneWay}" Margin="6"></TextBox>
                
    <TextBox x:Name="txtAgeTwo" Text="{Binding SAge,Mode=TwoWay}" Margin="6"></TextBox>
            
    </StackPanel>
            
            
    <TextBlock x:Name="tbSourceName" Width="150" FontSize="16" Foreground="Red" Grid.Row="1" Grid.Column="0" Text="当前数据源" TextAlignment="Left"></TextBlock>
            
    <ComboBox x:Name="cmbDataSource" Grid.Row="1" Grid.Column="1" Height="20"  Width="150" SelectionChanged="cmbDataSource_SelectionChanged"></ComboBox>
            
            
    <StackPanel Grid.Row="2" Grid.Column="0" Background="Bisque"  Orientation="Vertical" Margin="20">
                
    <TextBlock x:Name="dtbNameOne" Width="150" Text="姓名-TwoWay" TextAlignment="Center" FontSize="20" Foreground="Blue"   Margin="4"></TextBlock>
                
    <TextBlock x:Name="dtbAgeOne" Width="150" Text="年龄-TwoWay" TextAlignment="Center" FontSize="20" Foreground="Blue"  Margin="4"></TextBlock>
                
    <TextBlock x:Name="dtbNameTwo" Width="150" Text="姓名-TwoWay" TextAlignment="Center" FontSize="20" Foreground="Brown"  Margin="4"></TextBlock>
                
    <TextBlock x:Name="dtbAgeTwo" Width="150" Text="年龄-TwoWay" TextAlignment="Center" FontSize="20" Foreground="Brown"  Margin="4"></TextBlock>
            
    </StackPanel>
            
    <StackPanel Grid.Row="2" Grid.Column="1" Background="Aquamarine"  Orientation="Vertical" Margin="20">
                
    <TextBox x:Name="dtxtNameOne" Text="{Binding SName,Mode=TwoWay}" Margin="6" ></TextBox>
                
    <TextBox x:Name="dtxtAgeOne" Text="{Binding SAge,Mode=TwoWay}" Margin="6"></TextBox>
                
    <TextBox x:Name="dtxtNameTwo" Text="{Binding SName,Mode=TwoWay}" Margin="6"></TextBox>
                
    <TextBox x:Name="dtxtAgeTwo" Text="{Binding SAge,Mode=TwoWay}" Margin="6"></TextBox>
            
    </StackPanel>
             
        
    </Grid>
    </UserControl>
     Page.xaml.cs后台代码如下 :
    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace MyINotifyPropertyChanged
    {
        
    public partial class Page : UserControl
        {
           
            Student st 
    = new Student()
            {
                SName 
    = "Jack",
                SAge 
    = 25
            };

            StudentNotify stn 
    = new StudentNotify("Tom"26);

            
    public Page()
            {
                InitializeComponent();
                Loaded 
    +=new RoutedEventHandler(Page_Loaded);
            }

            
    private void Page_Loaded(object sender,EventArgs e)
            {      
                
    this.tbSourceName.Text = "当前数据源";
                
    this.cmbDataSource.Items.Add("有Notify");
                
    this.cmbDataSource.Items.Add("无Notify");
                
    this.cmbDataSource.SelectedIndex = 0;
                
    this.cmbDataSource.SelectedItem = 0;
            }

            
    private void cmbDataSource_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                
    switch (this.cmbDataSource.SelectedIndex)
                {
                    
    case 0this.LayoutRoot.DataContext = stn; break;
                    
    case 1this.LayoutRoot.DataContext = st; break;

                }
            }
        }
    }

    复制代码

    按下F5运行测试。
    测试过程:
    1、默认时我们先绑定有INotifyPropertyChanged接口的数据源,在测试界面,我们依次改变第二大组TextBox框的值(它们的BindingMode都是TwoWay),当改变生效时注意观察其它TextBox值的变化,我们可以看到只有OneTime设置的TextBox的值不受影响,其它相关TextBox都会随着数据源的变化的而变化,同时,在第二大组的TextBox的值的改变都会改变数据源的数据,因为它们的设置是TwoWay的。
    2、在测试界面,我们依次改改变第一大组的TextBox框内的值。我们可以看到只有TwoWay设置的TextBox的值会影响到数据源并进而影响到除OneTime设置TextBox框外的其它TextBox相关框的值。而其它设置的TextBox框内的值的改变则对数据源没有什么反向影响。
    3、我们改变绑定,数据源换成无INotifyPropertyChanged接口的数据源,再按上述方法改变TextBox框内的数据值,看看它们的变化,可以看出,此时TextBox内数据值的改变不再有与数据源通信的能力,而不论它们的Mode设置是什么值。