【1】Data Binding在WPF中的地位
从传统的Winform转移到WPF上,对于一个三层程序而言,数据存储层由数据库和文件系统组成,数据传输和处理仍然使用.NetFramework的ADO.NET等基本类(与Winform开发一样)。展示层则使用WPF类库来实现,而展示层和逻辑层的沟通就使用Data Binding来实现。可见,Data Binding在WPF中所起的作用就是高速公路的作用。有了这条高速公路,加工好的数据自动送达用户界面并加以显示,被用户修改过的数据也会自动传回业务逻辑层,一旦数据被加工好又会被送往界面。。。。
程序的逻辑层就像是一个强有力的引擎一直在运作,用加工好的数据驱动用户界面以文字、图形、动画等形式把数据显示出来------这就是数据驱动UI。
引入Data Binding之后,数据在逻辑层和用户界面直来之去、不涉及逻辑问题,这样的用户界面部分基本上不包含算法:Data Binding本身就是双向通信,对于多个UI元素关注同一个数据的情况,只需要用Data Binding将这些UI元素和数据一一关联上(以数据为中心的星形结构),当数据变化后,这些UI元素会同步显示这一变化。前面提到的问题也都迎刃而解了。更重要的是经过这样的优化,所有与业务逻辑相关的算法都处在业务逻辑层,逻辑层成了一个可以独立运转,完整的体系,而用户界面则不需要任何逻辑代码。完全依赖和从属于业务逻辑层。这样做有两个显而易见的好处,第一:如果把UI看做是应用程序的皮,把存储层和逻辑层看作是程序的瓤,我们可以很轻易的把皮撕下来换一个新的。第二:因为数据层能够独立运作,自成体系,所以我们可以进行更完善的单元测试而无需借助UI自动化测试工具----你完全可以把单元测试看作是一个“看不见的UI”,单元测试只是使用这个UI绕过真实的UI直接测试业务逻辑罢了。
【2】Binding 基础
如果把Binding比作数据的桥梁,那么它的两端分别是源(Source)和目标(Target)。数据丛哪里来哪里就是源,到哪里去哪里就是目标。一般情况下,Binding的源是业务逻辑层的对象,Binding的目标是UI层的控件对象。这样数据就会源源不断的通过Binding送达UI界面,被UI层展现,这就完成了数据驱动UI的过程。有了这座桥梁,我们不仅可以控制车辆在源与目标之间是双向通行还是单向通行。还可以控制数据的放行时机,甚至可以在桥上搭建一些关卡用来转换数据类型或者检验数据的正确性。
数据源是一个对象,一个对象本身可能会有很多数据,这些数据又通过属性暴露给外界。那么其中哪个元素是你想通过Binding送达UI元素的呢,换句话说,UI元素关心的是哪个属性值的变化呢?这个属性值称之为Binding的路径(Path)。但光有属性还不行-------Binding是一种自动机制,当值变化后属性要有能力通知Binding,让Binding把变化传递给UI元素。怎样才能让一个属性具备这种通知Binding值已经改变的能力呢?方法是在属性的Set语句中激发一个PropertyChanged事件。这个事件不需要我们自己声明,我们要做的事是让作为数据源的类实现System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会自动侦听来自这个接口PropertyChanged事件。
通过对Binding有了一个基本概念之后,让我们看一个最基本的例子。这个例子是创建一个简单的数据源并通过Binding把它连接到UI元素上。首先,我们创建一个名为"Student"的类,这个类的实例将作为数据源来使用。
C#:
class Student:INotifyPropertyChanged { private string _name; public event PropertyChangedEventHandler PropertyChanged; public string Name { get { return _name; } set { _name = value; // 通知UI,绑定的值发生了改变 if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); } } public int Id { set; get; } }
XAML:
<Window x:Class="WpfApplication6.wnd62" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="wnd62" Height="110" Width="525"> <StackPanel Background="LightSlateGray" Margin="5"> <TextBox x:Name="_txtBox" Margin="5" /> <Button Margin="5" Height="23" Click="Button_Click"/> </StackPanel> </Window>
Binding代码:
public partial class wnd62 : Window { Student _stu = new Student(); public wnd62() { InitializeComponent(); // 绑定数据 Binding binding = new Binding(); binding.Source = _stu; binding.Path = new PropertyPath("Name"); BindingOperations.SetBinding(_txtBox, TextBox.TextProperty, binding); //or //_txtBox.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu }); } private void Button_Click(object sender, RoutedEventArgs e) { _stu.Name = "wnd62"; } }
在准备Binding的部分,先使用“Binding binding = new Binding();”声明Binding类型变量并创建实例,然后使用“binding.Source=_stu;”为Binding实例指定数据源,最后使用“bind.Path= new PropertyPath(‘Name‘)”语句为Binding指定访问路径。
把数据源和目标连接在一起的任务是使用“BindingOperations.SetBinding(...)”方法完成的,这个方法的3个参数是我们记忆的重点:
第一个参数是指定Binding的目标
第二个参数指明目标的哪个数据。
第三个参数指定使用哪个Binding实例将数据源和目标关联起来。
更新的模型: