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

[ASP.net教程]WPF学习之Binding的学习(一)


程序的本质是数据加算法。通俗一点来说呢,其实就是用户给一个输入,经过算法的处理之后,计算机反馈一个输出给用户。可以很清楚的看出,在这个过程中,处于主导地位的是数据。但是,当我们在进行图形用户界面(Graphic User Interface,GUI)编程的时,数据总是处于被动地位。也就是说,程序总是在等待接收来自UI的消息/事件,在这些事件被处理之后,才会反馈给用户一个输出。我们用Data Binding可以在GUI编程时让数据回到程序的核心。 **1、Data Binding在WPF中的地位** 我们之前也提到过,程序的本质就是数据+算法。数据一般会在存储、逻辑和展示三个层进行流通,相对应的来讲,算法一般会分布在以下几处: A、数据库内部 B、读取和写入数据 C、业务逻辑 D、数据展示 E、界面与逻辑的交互 我们很容易能够理解,A、B两部分的算法一般很稳定,我们在编程的过程中很少去改动他们,同时他们的复用性也是很高。C这一部分包含大量的算法,因为其与客户的需求关系最为紧密,这也就导致这一部分的代码最复杂、变动最大。D、E两部分主要负责UI与逻辑的交互,也会有相应的算法。 显而易见,包含大部分代码的C部分最为重要,是开发的重中之重,但是在我们开发的过程中,D、E两个部分却经常成为麻烦的来源。问题的根源就在于逻辑层与展示层的地位不固定——当我们去编程实现用户的需求是,很显然逻辑层处于中心地位,但是在UI交互的过程中,展示层又处于中心地位。WPF作为一种专门的展示层技术,在其华丽的外观这种表层现象之下,更重要的是他在很层次上帮助程序员把思维的重心固定在逻辑层,无论在什么情况下,展示层总是处于从属地位。是什么让WPF拥有这种“超能力”呢?关键就在于WPF引进了Data Binding以及与之配套的Dependency Property和Data Template。 我们常常说在WPF开发中,是“数据驱动UI”,那么究竟什么事“数据驱动UI”呢?其实,在WPF编程中,Data Binding起到的作用就如同现实生活中的高速公路,有了他,加工好的数据就会自动传入到用户界面加以显示,被用户修改过的数据也会通过他自动回传到逻辑层……周而复始,程序的逻辑层就想一个引擎一样不停的运转。 在引入了Data Binding机制后,逻辑层和展示层之间就会是直来直去的,不涉及任何的逻辑问题。这样带来的好处就是用户界面不包含算法;而Data Binding本身就是双向通信,所以相当于将D、E两个部分合二为一。 **2、Binding基础** 什么事Binding?我们可以将Binding看做一个桥梁,他的两端分别是Source和Target。数据从哪里来,那么哪里就是source,到哪去那就是target。一般而言,Binding的源是逻辑层的对象,Binding的对象是UI层的控件对象。实现Binding后,数据就会源源不断的从逻辑层通过Binding送到UI层,UI层将这些数据进行展示,这就完成了数据驱动UI的过程。同时,在这个过程中,我们可以设置源于目标之间是双向通信还是单向通信,还可以在数据传送的过程中对数据的准确性进行校验甚至转换数据的类型。 下面,我们来看一个最简单的Binding的例子。 首先,我们创建一个Student的对象,让它作为数据源进行使用。

1 class Student2   {    3     private string _name;4     public string Name5     {6       get{return _name;}7       set{_name = value;}8     }    9   }

这个类很是简单,简单到只有一个string类型的Name属性。前面说过数据源是一个对象,一个对象本身可能会有很多数据,这些数据又通过属性暴露给外界。那么其中哪个元素是你想通过Binding送达UI元素的呢,换句话说,UI元素关心的是哪个属性值的变化呢?这个属性值称之为Binding的路径(Path)。但光有属性还不行-------Binding是一种自动机制,当值变化后属性要有能力通知Binding,让Binding把变化传递给UI元素。怎样才能让一个属性具备这种通知Binding值已经改变的能力呢?方法是在属性的Set语句中激发一个PropertyChanged事件。这个事件不需要我们自己声明,我们要做的事是让作为数据源的类实现System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会自动侦听来自这个接口PropertyChanged事件。**实现INotifyPropertyChanged接口的类看起来是这样:**

 1 class Student:INotifyPropertyChanged 2   { 3     public event PropertyChangedEventHandler PropertyChanged; 4     private string _name; 5  6     public string Name 7     { 8       get 9       {10         return _name;11       }12 13       set14       {15         _name = value;16         //激发事件17         if (PropertyChanged != null)18         {19           this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));20         }21       }22     }    23   }

当我们这样升级之后,只要Student中Name属性的值一变化,PropertyChanged事件就会被激发,Binding接收到这个事件后发现事件的消息告诉它是Name属性值发生了变化,于是通知Binding目标端的UI元素显示新的值。 现在,我们在窗体上准备一个Text和一个Button,代码如下:

 1 <Window x:Class="_1_Binding基础.MainWindow" 2     ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3     ="http://schemas.microsoft.com/winfx/2006/xaml" 4     ="http://schemas.microsoft.com/expression/blend/2008" 5     ="http://schemas.open 6     ="clr-namespace:_1_Binding基础" 7     mc:Ignorable="d" 8     Title="MainWindow" Height="110" Width="300"> 9   <Grid>10     <StackPanel>11       <TextBox Name="txtBoxName" Margin="5" BorderBrush="Black"></TextBox>12       <Button Content="Add Age" Click="Button_Click" Margin="5"></Button>13     </StackPanel>14   </Grid>15 </Window>

接下来,我们使用Binding将数据源和UI元素连接起来,具体代码如下:

 1 public partial class MainWindow : Window 2   { 3     Student stu; 4     public MainWindow() 5     { 6       InitializeComponent(); 7       //准备数据源 8       stu = new Student(); 9 10       //准备Binding11       Binding binding = new Binding();12       binding.Source = stu;13       binding.Path = new PropertyPath("Name");14 15       //使用Binding连接数据源与Binding目标16       BindingOperations.SetBinding(this.txtBoxName, TextBox.TextProperty, binding);17 18 19     }20 21     private void Button_Click(object sender, RoutedEventArgs e)22     {23       stu.Name += "Button";24     }25   }

下面我们逐一的解读一下这一段代码。在准备Binding的部分,首先用“Binding binding = new Binding();”声明Binding类型变量并创建实例,之后用“binding.Source = stu;”为Binding指定源,用“binding.Path = new PropertyPath("Name");”语句为Binding指定访问路径。把数据源和目标连接在一起的任务是使用“BindingOperations.SetBinding(...)”方法完成的,这个方法的3个参数是我们记忆的重点:第一个参数是指定Binding的目标,本例中的this.textBoxName。与数据源的Path原理类似,第二个参数用于为Binding指明为Binding指明把这个数据送达目标的哪个数据。第三个参数很明显,就是指定使用哪个Binding实例将数据源和目标关联起来。最后我们在Button的Click事件中对Name属性进行了更新,运行程序,点击Button,可以看到如下的结果:

 

先用这个例子作为基础,后面我们来研究Binding的每个特点。