Microsoft Expression Blend,Visual Studio 2010/2012/2013/2015
对于简单的界面布局以及基础的WPF学习,既可以使用Blend也可以使用VS,对于VS的版本没有必要要求最新的,版本间的差异不会影响基础的学习。 以后的代码我尽可能提供Blend和VS两个版本,代码差异出我会标注出来,请注意观察。 文章是从第六章开始写的,我会尽快把前五章补齐,请耐心等待……
WPF产生背景 程序界面经过了CUI(Console User Interface)到GUI(Graphic User Interface)的发展历程。 Windows GUI运行的机理是使用消息(Message)来驱动程序向前运行,消息的主要来源是用户的操作,比如单击鼠标、按下按钮,都会产生消息,消息会被Windows翻译并送达到目标程序然后被程序所处理。这种消息驱动机制迫使程序员把很多的精力放在了实现UI的编程上,这还不算完,随着程序UI的日趋复杂,UI层面上的代码与用于处理数据的逻辑代码也渐渐纠缠在一起变得难以维护。为了避免这样的问题,程序员们总结出了MVC(Model View Controler)和MVP(Model View Presenter)等诸多设计模式来把UI相关的代码与数据逻辑相关的代码分开。 为解决上面的问题WPF采用数据驱动UI的设计理念,将UI代码与数据逻辑代码进行分离。WPF作为一种专门的展示技术,华丽的外观和动画只是它的表层现象,更重要的是它在深层次上帮助程序员把思维的重心固定在了逻辑层,让展示层永远处于逻辑层的从属低位。WPF具有这种能力的关键是它引入了Data Binding概念以及与之配套的依赖属性(Dependency Property)系统和DataTemplate。Data Binding在WPF中的地位 Data Binding在WPF系统中起到的是数据高速公路的作用,有了这条高速公路,加工好的数据会自动送达用户界面加以显示,被用户修改过的数据也会自动传回到逻辑层,一旦数据被加工好后又会送达到用户界面……程序的逻辑层就像一个强有力的引擎不停的运转,用加工好的数据驱动程序的用户界面以文字、图形、动画等形式把数据显示出来——这就是“数据驱动UI”。
Binding模型图
Binding简单实例演示一般情况下,Binding源是逻辑层的对象,Binding目标是UI层的控件对象。通过Blend或VS创建一个WPF项目(因为后面牵扯到代码的修改建议用VS,VS中的智能提示做的比Blend要好),然后添加一个Student的类,如下:
Student类代码如下:class Student{ private string name; public string Name { get{return name;} set{name=value;} }}
改造Student类 在进行绑定时要确认绑定的源,绑定源的属性(即绑定的路径Path)以及绑定的目标对象的属性。本例简单Binding的源即Student对象,Binding源的属性即Student对象的Name属性,目标对象的属性一会进行设置。 到目前为止光有属性还不行,Binding是一种自动机制,当值变化后属性要有能力通知Binding,让Binding把变化传递给UI元素。可以通过设置属性的set语句激发一个PropertyChanged事件,这个事件不用我们自己声明,我们要做的是让数据源的类实现System.ComponetModel命名空间中的INotifyPropertyChanged接口,当为Binding设置了数据源后,Binding就会自动侦听来自这个接口的PropertyChanged事件。代码如下:class Student : INotifyPropertyChanged{ public event PropertyChangedEventHandler PorpertyChanged; private string name; public string Name { get{return name;} set { name=value; if (this.PorpertyChanged!=null) { this.PorpertyChanged.Invoke(this, new PropertyChangedEventArgs('Name')); } } }}
设置主窗体在主窗体上添加TextBox和Button,其中TextBox为Binding的目标对象。主窗体的XAML代码如下:
使用Binding连接数据源和目标UIpublic partial class MainWindow : Window{ Student stu; public MainWindow() { InitializeComponent(); //准备数据源 stu = new Student(); //准备Binding Binding bd = new Binding(); bd.Source = stu; bd.Path = new PropertyPath('Name'); //使用Binding连接数据源和目标 BindingOperations.SetBinding(this.txtName, TextBox.TextProperty, bd); } private void Button_Click(object sender, RoutedEventArgs e) { stu.Name += 'Name'; }}点击按钮效果如下图:
BindingOperations.SetBinding方法的三个参数(1)指定Binding的目标,本例中为this.txtName(2)用于为Binding指明把数据送达到目标的哪个属性。只是你会发现这里用的不是对象的属性而是类的一个静态只读的DependencyProperty类型成员变量!这类属性的值可以通过Binding依赖在其他对象的属性值上,被其他对象的属性值所驱动(3)指定使用哪个Binding实例将数据源和目标关联起来
Binding的进一步简化因为TextBox这类UI元素的基类FrameworkElement对BindingOperations.SetBinding(...)方法进行了封装,其封装的结果也叫SetBinding,只是参数列表发生了变化。封装代码如下:public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){ return BindingOperations.SetBinding(this,dp,binding);}基于上面的封装对Binding的代码可进行如下的简化:public MainWindow(){ InitializeComponent(); this.SetBinding(TextBox.TextProperty, new Binding('Name') { Source=stu});}