wpf中数据绑定和INotifyPeropertyChanged的理解
原创:转载请注明出处。
先说数据绑定:
XAML代码:
<Window x:Class="数据绑定和INotifyPropertyChanged.Window1" Loaded="Window_Loaded" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="数据绑定和INotifyPropertyChanged" Height="300" Width="300"> <Grid> <Label Height="28" Margin="15,35,0,0" Name="lbAge" VerticalAlignment="Top" HorizontalAlignment="Left" Width="42">年龄:</Label> <Label Height="28" HorizontalAlignment="Left" Margin="15,83,0,0" Name="lbName" VerticalAlignment="Top" Width="42">姓名:</Label> <TextBox Height="23" Margin="79,37,79,0" Name="TxtAge" VerticalAlignment="Top" Text="{Binding Name}"/> <TextBox Height="23" Margin="79,83,79,0" Name="TxtName" VerticalAlignment="Top" Text="{Binding Age}"/> </Grid> </Window>
C#代码:
步骤如下:
先定义一个类
1 public class Person:INotifyPropertyChanged 2 { 3 private string _name; 4 5 public string Name 6 { 7 get { return _name; } 8 set { _name = value; } 9 } 10 11 private int _age; 12 13 public int Age 14 { 15 get { return _age; } 16 set { _age = value; } 17 } 18 }
然后在后台写代码:
1 private Person p1; 2 3 public Person P1 4 { 5 get { return p1; } 6 set { p1 = value; } 7 } 8 public Window1() 9 { 10 InitializeComponent(); 11 } 12 13 private void Window_Loaded(object sender, RoutedEventArgs e) 14 { 15 p1 = new Person(); 16 p1.Name = "aaa"; 17 p1.Age = 15; 18 19 TxtAge.DataContext = p1; 20 TxtName.DataContext = p1; 21 }
注意:
这里牵扯到一个很重要的东西,“数据上下文”,即DataContext,必须把界面控件的DataContext和类的实例绑定起来,这样界面才会显示类中属性的值。
要想控件获得类中的属性值并显示,控件必须绑定类中的属性。
接下来说一下INotifyPropertyChanged,这个是MVVM的基础,也是数据双向绑定很重要很关键的部分。通过他,类的属性值改变才会改变UI界面显示的值。(有一个很重要的知识点:事件,这个不懂得赶紧去学下再来接着往下看)。
上代码,这个代码是数据绑定部分代码的基础上进一步完善。
XMAL代码:
1 <Window x:Class="数据绑定和INotifyPropertyChanged.Window1" Loaded="Window_Loaded" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="数据绑定和INotifyPropertyChanged" Height="300" Width="300"> 5 <Grid> 6 <Label Height="28" Margin="15,35,0,0" Name="lbAge" VerticalAlignment="Top" HorizontalAlignment="Left" Width="42">年龄:</Label> 7 <Label Height="28" HorizontalAlignment="Left" Margin="15,83,0,0" Name="lbName" VerticalAlignment="Top" Width="42">姓名:</Label> 8 <TextBox Height="23" Margin="79,37,79,0" Name="TxtAge" VerticalAlignment="Top" Text="{Binding Name}"/> 9 <TextBox Height="23" Margin="79,83,79,0" Name="TxtName" VerticalAlignment="Top" Text="{Binding Age}"/> 10 <Button Height="23" HorizontalAlignment="Left" Margin="30,0,0,80" Name="BtnAgePP" VerticalAlignment="Bottom" Width="75" Click="BtnAgePP_Click">Age++</Button> 11 <Button Height="23" Margin="132,0,71,80" Name="BtnDisplayAge" VerticalAlignment="Bottom" Click="BtnDisplayAge_Click">显示年龄</Button> 12 </Grid> 13 </Window>
C#代码:
1 private Person p1; 2 3 public Person P1 4 { 5 get { return p1; } 6 set { p1 = value; } 7 } 8 public Window1() 9 { 10 InitializeComponent(); 11 } 12 13 private void Window_Loaded(object sender, RoutedEventArgs e) 14 { 15 p1 = new Person(); 16 p1.Name = "aaa"; 17 p1.Age = 15; 18 19 TxtAge.DataContext = p1; 20 TxtName.DataContext = p1; 21 } 22 23 private void BtnDisplayAge_Click(object sender, RoutedEventArgs e) 24 { 25 MessageBox.Show(p1.Age.ToString()); 26 MessageBox.Show(p1.Name); 27 } 28 29 private void BtnAgePP_Click(object sender, RoutedEventArgs e) 30 { 31 p1.Age++; 32 p1.Name = "ccc"; 33 }
类:person也要改,
1 public class Person:INotifyPropertyChanged 2 { 3 private string _name; 4 5 public string Name 6 { 7 get { return _name; } 8 set { _name = value; if (PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs("Name")); } } 9 } 10 11 private int _age; 12 13 public int Age 14 { 15 get { return _age; } 16 set { _age = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Age")); } } 17 } 18 19 #region INotifyPropertyChanged 成员 20 21 public event PropertyChangedEventHandler PropertyChanged;//数据绑定会监听这个PropertyChanged事件 22 23 #endregion 24 }
有没有注意到类Person有什么变化,对,Person类实现了INotifyPropertyChanged接口。
解释一下:
1、Person类实现INotifyPropertyChanged接口,这个接口只有一个PropertyChanged事件成员。
看源码:
1 // 摘要: 2 // 向客户端发出某一属性值已更改的通知。 3 public interface INotifyPropertyChanged 4 { 5 // 摘要: 6 // 在更改属性值时发生。 7 event PropertyChangedEventHandler PropertyChanged; 8 }
2、数据绑定会检测Person类是否实现了INotifyPropertyChanged接口,
3、如果Person类实现了INotifyPropertyChanged接口,那就监听PropertyChanged事件。
4、如果Property改变了,那么就产生PropertyChanged事件,即PropertyChanged!=null。
5、向前端UI发送属性值改变的额通知,控件绑定了属性,控件收到属性改变的通知,就把自身的值也改变 。
补充:在数据绑定的时候,是一个一个控件绑定的,当控件少的时候这没问题,但是控件多的话,就要重复写很多次的datacontext了。这时候,可以用this.DataContext来统一指定当前窗口的所有控件的数据上下文。
譬如,本文中的例子可以变成this.DataContext = p1。这样的话,DataContext就可以作用到全部的控件,而不需要一个一个去指定了。
当然,也可以在this的DataContext指定后,给某个控件指定DataContext,这样子特定的控件就有它自己的DataContext了。