WPF之数据绑定基础
关于WPF的数据绑定,本人愚见,将其分为两大类。一类为绑定到界面元素的属性,多用于一些界面设计中,以本人目前的眼界来看,此类需求相对较少;另一类则为用户数据的绑定,多用于数据展示。
下面就几个简单的小例子,阐述下这两种绑定的一些基本做法。
一、绑定到界面元素
绑定到界面元素,相对比较容易,这里用一个简单的例子简要说明下基本的语法。
<Window x:Class="BindPracitce.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <StackPanel> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Background="Gray" Foreground="White" Width="100" Height="30" x:Name="OriginalText" Text="{Binding ElementName=OriginalText2,Path=Text,Mode=OneWay}" /> <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Width="100" Text="{Binding ElementName=OriginalText,Path=Text,Mode=OneWayToSource,UpdateSourceTrigger=LostFocus}"/> <TextBox Width="100" x:Name="OriginalText2"/> </StackPanel> </Grid> </Window>
通常使用时,用ElementName来查找元素,Path来控制要绑定的属性(注意这里不用Property,是因为Path指向的更深),Mode来确定绑定的方向,UpdateSourceTrigger用来确定属性更改的时机。
Mode有五种枚举值,OneWay、TwoWay、OnWayToSource、Default以及OneTime。OneWay,当源属性变化时更新目标属性。TwoWay,双向绑定,源跟目标都会跟随对方的变动而变动,开销要大些。OneWayToSource,反向的,目标属性变化时更新源属性。Default,默认的,一般来说,对于用户可以设置的(如TextBox.Text属性)是双向的,而其他则是单向的。OneTime,只绑定一次,其后源属性的改变都不会引起目标属性的变化(除非调用BindingExpression.UpdateTarget()方法),此模式可以降低点开销。
上面的例子演示了OneWay和OneWayToSource的用法,值得一提的是,上面TextBlock的Text属性同时受两个TextBox的影响,但坑爹的是,下面那个TextBox与TextBlock的绑定被破坏了(尚不知是何原因),解决的办法就是,将TextBlock的绑定由OneWay改为TwoWay。另外,UpdateSourceTrigger的使用场合是OneWayToSource或是TwoWay。
二、绑定到用户数据
关于WPF的数据绑定园子里例子不少,通常一些比较繁杂的业务往往涉及到一些复杂的绑定及层次绑定之类的,这里仅仅展示一个最基本的例子,让初学者能够快速了解绑定的基础,至于一些繁杂的数据绑定往往需要结合业务处理,此类文章可以参考下msdn上的例子。
下面的例子展示如何将一个用户类的属性绑定到控件。
一个简单的用户类。
public class Person { public string ID { get; set; } public string Name { get; set; } }
XAML中这么绑定。
<StackPanel Margin="10" Orientation="Horizontal" Height="30" x:Name="PersonPanel"> <TextBlock Text="ID:" VerticalAlignment="Center"/> <TextBox Width="100" Text="{Binding Path=ID}" VerticalAlignment="Center"/> <TextBlock Text="Name:" VerticalAlignment="Center" Margin="20 0 0 0"/> <TextBox Width="100" Text="{Binding Path=Name}" VerticalAlignment="Center"/> <Button Content="Change Properties" x:Name="ChangeButton" Margin="20 0 0 0"/> </StackPanel>
然后在后台代码中添加数据源(设置DataContext属性)。
void MainWindow_Loaded(object sender, RoutedEventArgs e) { Person p= new Person() { ID="001", Name="TestPerson" }; PersonPanel.DataContext = p; ChangeButton.Click += (s0, e0) => { p.ID = "002"; p.Name = "TestPerson2"; }; }
OK,现在运行程序,两个TextBox中分别显示001和TestPerson,至此我们已经完成了数据的绑定了。
然而事实上,我们有很多地方需要处理属性的更改的,而普通属性是做不到这点的。像上面的例子,单击按钮,TextBox中的数据不会出现任何变化。依赖项属性支持属性变更通知,所以将Person中的属性都改为依赖项属性是可以实现这个效果的,不过据个人理解,依赖项属性通常用于界面元素(关于依赖项属性,这篇文章讲解很到位 WPF基础到企业应用系列7——深入剖析依赖属性)。而更常见的做法是,让我们的类实现INotifyPropertyChanged接口。为了方便代码复用,我们可以使用一个基类来实现。
public class ModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
现在让我们的业务类继承此基类,然后在设置属性时触发OnPropertyChanged事件就行了,当然你还可以在这个基类中添加一些状态信息之类的。
public class Person : ModelBase { private string Id; public string ID { get { return Id; } set { Id = value; OnPropertyChanged("ID"); } } private string name; public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } }
好了,现在再点击按钮时,TextBox中的文本就会变成002和TestPerson2了。