看来WPF如此之炫,但算法在3层中的分布是不均匀的

WPF之Binding【转】

1,Data Binding在WPF中的地位

 

次第的武夷山真面目是数据+算法。数据会在储存、逻辑和界面三层之间流通,所以站在数额的角度上来看,那三层都很关键。但算法在3层中的分布是不均匀的,对于二个3层结构的先后来说,算法一般分布在这几处:

阅览WPF如此之炫,也想用用,但是一点也不会呀。

A。数据库内部。

从必要谈起呢:

B。读取和写回数据。

率先可能要做叁个很炫的界面。见MaterialDesignInXAMLToolKit.

C。业务逻辑。

那,最根本的吧,还是想呈现数据。

D。数据展现。

就先来数量,数据足以从数据Curry获得,可是怎样彰显出来吗?

E。界面与逻辑的相互。

本文的栋梁出来了:(以下内容全转发旁人,具体 原来的书文见上边包车型客车链接)

A,B两有的的算法一般都不行平稳,不会随随便便去改变,复用性也很高;C处与客户供给最紧凑,最复杂,变化最大,大多少算法都汇聚在那边。D,E负责UI和逻辑的相互,也占有一定量的算法。

====================================

旗帜显著,C部分是先后的着力,是付出的要紧,所以大家相应把精力集中在C部分。然则,D,E两片段却平时成为麻烦的来源。首先那两有些都与逻辑严厉有关,一十分的大心就有或许把自然该放在逻辑层里面包车型地铁算法写进那两局地(所以才有了MVC、MVP等情势来制止那种情景出现)。其次,那两部分以新闻仍然事件的方法与逻辑层沟通,一旦出现同四个多少必要在多出显示/修改时,用于共同的代码错综复杂;最终,D和E本来是互逆的一对儿。但却须求分开来写—–显示数据写二个算法,修改数据再写二个算法。不问可见导致的结果正是D和E两某个会占去一部分算法,搞糟糕还会牵涉不少生气。

1,Data Binding在WPF中的地位

标题标来源于在于逻辑层和出示层的地点不定点——当达成客户需求的时候,逻辑层的确处于大旨地位。但到了贯彻UI的时候,体现层又远在宗旨的地位。WPF作为一种标准的彰显层技术,华丽的外观和卡通只是它的表层现象,最关键的是她在深层次上把程序员的合计定势在了逻辑层,让体现层永远处于逻辑层的附属地位。WPF具有那种力量的关键在于它引入了Data
Binding概念及与之配套的Dependency Property系统和DataTemplate。

次第的本来面目是多少+算法。数据会在存款和储蓄、逻辑和界面三层之间流通,所以站在数据的角度上来看,那三层都很首要。但算法在3层中的分布是不均匀的,对于3个3层结构的程序来说,算法一般分布在这几处:

从观念的Winform转移到WPF上,对于二个三层程序而言,数据存款和储蓄层由数据库和文件系统组成,数据传输和处理依旧使用.NetFramework的ADO.NET等基本类(与Winform开发一样)。体现层则动用WPF类库来兑现,而显示层和逻辑层的联络就选用Data
Binding来兑现。可知,Data
Binding在WPF中所起的法力正是高速公路的机能。有了那条高速公路,加工好的数目自动送达用户界面并加以展现,被用户修改过的数额也会自动传回业务逻辑层,一旦数据被加工好又会被送往界面。。。。程序的逻辑层就好像二个有力的引擎一贯在运行,用加工好的数据驱动用户界面也文字、图形、动画等花样把多少彰显出来——这便是数量驱动UI。

A。数据库内部。

引入Data
Binding之后,D,E两有些被简化了不少。首先,数据在逻辑层和用户界面直来之去、不涉及逻辑难点,这样的用户界面部分基本上不带有算法:Data
Binding本人正是双向通讯,所以一定于把D和E合两为一;对于多少个UI成分关切同一个数据的景况,只必要用Data
Binding将那些UI成分和数码一一关联上(以多少为宗旨的星形结构),当数码变化后,那么些UI成分会联手彰显这一变动。前边提到的题材也都消除了。更要紧的是通过这么的优化,全数与作业逻辑相关的算法都地处工作逻辑层,逻辑层成了多个足以独自运转,完整的体系,而用户界面则不须求任何逻辑代码。完全依靠和从属于工作逻辑层。那样做有八个显著的补益,第3:若是把UI看做是应用程序的皮,把存款和储蓄层和逻辑层看作是先后的瓤,我们得以很轻易的把皮撕下来换2个新的。第壹:因为数据层可以独立运转,自成体系,所以咱们得以展开更周详的单元测试而无需借助UI自动化测试工具—-你一点一滴能够把单元测试看作是1个“看不见的UI”,单元测试只是利用那些UI绕过真实的UI直接测试工作逻辑罢了。

B。读取和写回数据。

2 ,  Binding 基础

C。业务逻辑。

若是把Binding比作数据的桥梁,那么它的两岸分别是源(Source)和指标(Target)。数据丛哪个地方来何地就是源,到何地去哪个地方就是指标。一般景况下,Binding的源是业务逻辑层的靶子,Binding的靶子是UI层的控件对象。那样数据就会接连不断的经过Binding送达UI界面,被UI层展现,那就大功告成了数额驱动UI的经过。有了那座大桥,大家不光能够操纵车辆在源与对象之间是双向通行或然单向通行。还足以控制数据的放行时机,甚至能够在桥上搭建部分关卡用来转换数据类型大概检验数据的正确性。

D。数据显示。

通过对Binding有了一个基本概念之后,让我们看四个最基本的事例。那些事例是开创三个总结的数据源并由此Binding把它总是到UI成分上。

E。界面与逻辑的互动。

首先,我们创立1个名为”Student”的类,那几个类的实例将作为数据源来使用。

A,B两片段的算法一般都不行平稳,不会自由去改变,复用性也很高;C处与客户供给最紧凑,最复杂,变化最大,大多少算法都集中在此地。D,E负责UI和逻辑的相互,也侵夺一定量的算法。

 

了解,C部分是程序的中坚,是付出的机要,所以大家应该把精力集中在C部分。然则,D,E两有个别却时常成为麻烦的根源。首先那两有的都与逻辑严密相关,一相当大心就有或许把本来该放在逻辑层里面包车型大巴算法写进那两部分(所以才有了MVC、MVP等格局来制止那种场地出现)。其次,那两有个别以音信仍好玩的事件的法子与逻辑层交换,一旦出现同叁个数目需求在多出显示/修改时,用于共同的代码错综复杂;最终,D和E本来是互逆的一对儿。但却供给分开来写—–呈现数据写三个算法,修改数据再写3个算法。显而易见导致的结果便是D和E两局地会占去一部分算法,搞不好还会牵涉不少走上坡路。

[csharp] view
plain
copyprint?

题指标根源在于逻辑层和出示层的身份不定点——当完成客户须要的时候,逻辑层的确处于大旨地位。但到了贯彻UI的时候,体现层又处在宗旨的身价。WPF作为一种标准的来得层技术,华丽的外观和卡通片只是它的外表现象,最重点的是她在深层次上把程序员的思辨定势在了逻辑层,让展现层永远处于逻辑层的直属地位。WPF具有那种力量的关键在于它引入了Data
Binding概念及与之配套的Dependency Property系统和DataTemplate。

 

从古板的Winform转移到WPF上,对于三个三层程序而言,数据存款和储蓄层由数据库和文件系统组成,数据传输和处理照旧使用.NetFramework的ADO.NET等基本类(与Winform开发一样)。体现层则应用WPF类库来达成,而体现层和逻辑层的牵连就应用Data
Binding来兑现。可知,Data
Binding在WPF中所起的功能正是高速公路的功能。有了那条高速公路,加工好的多寡自动送达用户界面并加以呈现,被用户修改过的数据也会自行传回业务逻辑层,一旦数据被加工好又会被送往界面。。。。程序的逻辑层就像二个强硬的引擎一直在运作,用加工好的数码驱动用户界面也文字、图形、动画等花样把数量呈现出来——那正是数据驱动UI。

  1. public class Student  
  2.     {  
  3.         private string name;  
  4.   
  5.         public string Name  
  6.         {  
  7.             get { return name; }  
  8.             set  
  9.             {  
  10.                 name = value;  
  11.         }  
  12.     }  

引入Data
Binding之后,D,E两局地被简化了无数。首先,数据在逻辑层和用户界面直来之去、不关乎逻辑难点,那样的用户界面部分基本上不分包算法:Data
Binding本人正是双向通讯,所以一定于把D和E合两为一;对于多少个UI成分关切同二个数据的场合,只必要用Data
Binding将那么些UI成分和数据一一关联上(以数量为骨干的星形结构),当数码变动后,这一个UI成分会一起展现这一生成。前面提到的题材也都消除了。更关键的是透过这么的优化,全体与事务逻辑相关的算法都远在业务逻辑层,逻辑层成了八个可以独自运行,完整的种类,而用户界面则不要求此外逻辑代码。完全依靠和从属于工作逻辑层。那样做有四个显明的便宜,第叁:假设把UI看做是应用程序的皮,把存款和储蓄层和逻辑层看作是先后的瓤,大家得以很自由的把皮撕下来换二个新的。第一:因为数据层能够单独运营,自成类别,所以大家得以拓展更全面的单元测试而无需借助UI自动化测试工具—-你一点一滴能够把单元测试看作是三个“看不见的UI”,单元测试只是接纳这么些UI绕过真正的UI直接测试工作逻辑罢了。

那个类很简短,不难到唯有三个string类型的Name属性。后面说过数据源是1个目的,四个对象自笔者也许会有多如牛毛数量,这个多少又经过质量暴露给外界。那么内部哪个成分是你想透过Binding送达UI成分的呢,换句话说,UI成分关切的是哪个属性值的生成呢?这一个属性值称之为Binding的路子(Path)。但光有总体性还格外——-Binding是一种斯特林发动机制,当班值日变化后属性要有能力公告Binding,让Binding把转变传递给UI成分。如何才能让叁天性子具备那种公告Binding值已经转移的能力啊?方法是在品质的Set语句中刺激3个PropertyChanged事件。这些事件不须求我们协调证明,大家要做的事是让作为数据源的类完成System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会活动侦听来自那么些接口PropertyChanged事件。

2 ,  Binding 基础

 

万一把Binding比作数据的大桥,那么它的双面分别是源(Source)和对象(Target)。数据丛哪个地方来哪儿正是源,到何地去何地就是目的。一般景况下,Binding的源是事情逻辑层的靶子,Binding的靶子是UI层的控件对象。那样数据就会接踵而至 蜂拥而至的通过Binding送达UI界面,被UI层突显,那就完了了数码驱动UI的经过。有了那座桥梁,大家不光能够决定车子在源与指标之间是双向通行大概单向交通。还是能控制数据的放行时机,甚至足以在桥上搭建部分关卡用来更换数据类型只怕检验数据的没错。

兑现INotifyPropertyChanged接口的类看起来是那样:

因而对Binding有了3个基本概念之后,让大家看一个最主旨的例子。这些例子是创立三个大约的数据源并透过Binding把它连接到UI成分上。

 

率先,大家创制二个名为”Student”的类,这些类的实例将用作数据源来使用。

[csharp] view
plain
copyprint?

 

 

[csharp] view
plain
 copy

  1. public class Student : INotifyPropertyChanged  
  2.     {  
  3.         private string name;  
  4.   
  5.         public string Name  
  6.         {  
  7.             get { return name; }  
  8.             set  
  9.             {  
  10.                 name = value;  
  11.                 if (PropertyChanged != null)  
  12.                 {  
  13.                     this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(“Name”));  
  14.                 }  
  15.             }  
  16.         }  
  17.         public event PropertyChangedEventHandler PropertyChanged;  
  18.     }  

 

因此那样一升任,当Name属性的值发生变化时PropertyChanged事件就会被激起,Binding接收到那个事件后意识事件的信息告知它是Name属性值产生了转变,于是通告Binding目的端的UI元素展现新的值。

 print?

 

  1. public class Student  
  2.     {  
  3.         private string name;  
  4.   
  5.         public string Name  
  6.         {  
  7.             get { return name; }  
  8.             set  
  9.             {  
  10.                 name = value;  
  11.         }  
  12.     }  

接下来大家在窗体上准备一个TextBox和Button,代码如下:

那一个类非常粗大略,简单到唯有三个string类型的Name属性。前边说过数据源是3个对象,2个对象自作者也许会有这些数据,这一个数据又通过品质揭破给外界。那么内部哪个成分是您想经过Binding送达UI成分的呢,换句话说,UI成分关切的是哪些属性值的扭转吗?这么些属性值称之为Binding的门路(帕特h)。但光有质量还卓殊——-Binding是一种发动机制,当班值日变化后属性要有力量公告Binding,让Binding把转变传递给UI成分。怎样才能让1个属性具备那种布告Binding值已经济体改成的力量呢?方法是在品质的Set语句中激发三个PropertyChanged事件。这几个事件不要求大家协调证明,大家要做的事是让作为数据源的类达成System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会自动侦听来自那个接口PropertyChanged事件。

 

 

[html] view
plain
copyprint?

兑现INotifyPropertyChanged接口的类看起来是那般:

 

 

  1. <Window x:Class=”WpfApplication1.MainWindow”  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”MainWindow” Height=”350″ Width=”525″>  
  5.     <Grid>  
  6.         <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”185,43,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ />  
  7.         <Button Content=”Button” Height=”23″ HorizontalAlignment=”Left” Margin=”209,96,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”75″ Click=”button1_Click” />  
  8.     </Grid>  
  9. </Window>  

[csharp] view
plain
 copy

后台代码那样写:

 

 

 print?

 

  1. public class Student : INotifyPropertyChanged  
  2.     {  
  3.         private string name;  
  4.   
  5.         public string Name  
  6.         {  
  7.             get { return name; }  
  8.             set  
  9.             {  
  10.                 name = value;  
  11.                 if (PropertyChanged != null)  
  12.                 {  
  13.                     this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(“Name”));  
  14.                 }  
  15.             }  
  16.         }  
  17.         public event PropertyChangedEventHandler PropertyChanged;  
  18.     }  

[csharp] view
plain
copyprint?

通过这么一荣升,当Name属性的值发生变化时PropertyChanged事件就会被鼓舞,Binding接收到这些事件后发觉事件的音信告知它是Name属性值发生了扭转,于是公告Binding目的端的UI成分呈现新的值。

 

 

  1. /// <summary>  
  2.    /// MainWindow.xaml 的相互逻辑  
  3.    /// </summary>  
  4.    public partial class MainWindow : Window  
  5.    {  
  6.        Student stu = null;  
  7.        public MainWindow()  
  8.        {  
  9.            InitializeComponent();  
  10.            stu = new Student();  
  11.            Binding bind = new Binding();  
  12.            bind.Source = stu;  
  13.            bind.Path = new PropertyPath(“Name”);  
  14.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  15.   
  16.        }  
  17.   
  18.        private void button1_Click(object sender, RoutedEventArgs e)  
  19.        {  
  20.            stu.Name += “f”;  
  21.            new Window1().Show();  
  22.        }  
  23.    }  

下一场我们在窗体上准备贰个Text博克斯和Button,代码如下:

让大家逐句解释一下那段代码,那段代码是MainWIndow的后台代码,它的前端代码正是地方的XAML代码。“Student
stu;”是为MainWindow声雀巢个Student类型的成员变量,那样做的目标是为着在MainWindow的构造器和Button.Click事件处理器中都能够访问到由它引用的Student实例(数据源)。

 

 

[html] view
plain
 copy

在MainWindow的构造器中“InitializeComponent();”是自动生成的代码,用途是开始化UI成分。“stu=new
Student();”那句是创立1个Student实例并用stu成员变量引用它,那个指标正是大家的数据源。

 

在备选Binding的有个别,先利用“Binding bind = new
Binding();”评释Binding类型变量并创办实例,然后利用“bind.Source=stu;”为Binding实例钦定数据源,最终选择“bind.Path=
new PropertyPath(‘Name’)”语句为Binding钦定访问路径。

 print?

把数据源和对象连接在一起的任务是使用“BindingOperations.SetBinding(…)”方法成功的,那么些办法的叁个参数是大家记念的最首要:

  1. <Window x:Class=”WpfApplication1.MainWindow”  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”MainWindow” Height=”350″ Width=”525″>  
  5.     <Grid>  
  6.         <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”185,43,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ />  
  7.         <Button Content=”Button” Height=”23″ HorizontalAlignment=”Left” Margin=”209,96,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”75″ Click=”button1_Click” />  
  8.     </Grid>  
  9. </Window>  

率先个参数是内定Binding的目的,本例中的this.textBoxName。

后台代码那样写:

与数据源的Path原理类似,第一个参数用于为Binding指明为Binding指明把那几个数量送达目的的哪位数据。

 

其四个参数很显眼,正是点名使用哪个Binding实例将数据源和对象关联起来。

 

运作程序,单击按钮咱们将会合到如下的职能图:

[csharp] view
plain
 copy

图片 1

 

透过地点的事例,大家早就在脑子中确立起来如图所示的模型

 print?

图片 2

  1. /// <summary>  
  2.    /// MainWindow.xaml 的互动逻辑  
  3.    /// </summary>  
  4.    public partial class MainWindow : Window  
  5.    {  
  6.        Student stu = null;  
  7.        public MainWindow()  
  8.        {  
  9.            InitializeComponent();  
  10.            stu = new Student();  
  11.            Binding bind = new Binding();  
  12.            bind.Source = stu;  
  13.            bind.Path = new PropertyPath(“Name”);  
  14.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  15.   
  16.        }  
  17.   
  18.        private void button1_Click(object sender, RoutedEventArgs e)  
  19.        {  
  20.            stu.Name += “f”;  
  21.            new Window1().Show();  
  22.        }  
  23.    }  

先用这么些做基础,前边大家将讨论Binding的各类特点。

让我们逐句解释一下那段代码,那段代码是MainWIndow的后台代码,它的前端代码正是地点的XAML代码。“Student
stu;”是为MainWindow声澳优个Student类型的分子变量,那样做的目标是为了在MainWindow的构造器和Button.Click事件处理器中都能够访问到由它引用的Student实例(数据源)。

1.3         Binding的源与途径

 

Binding
的源也便是多少的源头。Binding对源的要求并不苛刻——只要它是二个目的,并且经过品质(Property)公开自个儿的多寡,它就能当做Binding
的源。

在MainWindow的构造器中“InitializeComponent();”是自动生成的代码,用途是开头化UI成分。“stu=new
Student();”那句是成立三个Student实例并用stu成员变量引用它,那个目的正是大家的数据源。

前边七个例证已经向我们表明,假如想让作为Binding源的指标拥有电动公告Binding自身属性值已经已经成形的力量。那么就供给让类完结INotifyChanged接口并在性质的Set语句中激发PropertyChanged事件。在常常生活中,除了利用那种对象作为数据源之外,我们还有更多的选料,比如控件把团结的容器或子集成分当源、用叁个控件做为另一个控件的数据源,把集同盟为ItemControl的数据源、使用XML作为TreeView或Menu的数据源。把七个控件关联到3个“数据制高点”上,甚至干脆不给Binding内定数据源、让他自身去找。上面大家就分述那几个处境。

在备选Binding的有的,先选取“Binding bind = new
Binding();”表明Binding类型变量并创建实例,然后利用“bind.Source=stu;”为Binding实例钦定数据源,最后选取“bind.帕特h=
new PropertyPath(‘Name’)”语句为Binding钦点访问路径。

1.3.1       把控件作为Binding源与Binding标记扩充。

把数据源和目的连接在一块儿的天职是应用“BindingOperations.SetBinding(…)”方法成功的,那几个方式的2个参数是我们纪念的重要:

前面讲过,大部分处境下Binding的源是逻辑层对象,但局地时候为了让UI发生联合浮动成效也会采用Binding在控件间建立关联。上边包车型大巴代码是啊三个TextBox的Text属性关联到Slider的Value的习性上。

先是个参数是钦点Binding的对象,本例中的this.textBoxName。

 

与数据源的Path原理类似,第3个参数用于为Binding指明为Binding指明把那些数量送达指标的哪些数据。

[html] view
plain
copyprint?

其多个参数很显明,就是钦点使用哪个Binding实例将数据源和对象关联起来。

 

运维程序,单击按钮大家将会看出如下的效劳图:

  1. <Window x:Class=”WpfApplication1.Window1″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window1″ Height=”321″ Width=”401″>  
  5.     <Grid>  
  6.         <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  
  7.         <Slider Height=”23″ HorizontalAlignment=”Left” Margin=”84,106,0,0″ Name=”slider1″ VerticalAlignment=”Top” Width=”212″ />  
  8.         <Button Content=”Button” Height=”23″ HorizontalAlignment=”Left” Margin=”166,197,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”75″ Click=”button1_Click” />  
  9.     </Grid>  
  10. </Window>  

图片 3

运行效果如下图:

通过上边的例证,大家曾经在脑子中创建起来如图所示的模型

 

图片 4

图片 5
正如大家所见,除了能够在C#中确立Binding外在XAML代码里也得以便宜的设置Binding,这就给设计师十分的大的自由度来控制UI成分之间的关联情形。值得注意的是,在C#代码中,能够访问在XAML中评释的变量不过XAML中不能够访问C#中扬言的变量,由此,要想在XAML中树立UI成分和逻辑对象的Binding还要颇费些周折,把逻辑代码注明为XAML中的能源(Resource),我们放能源一章去讲。

先用那些做基础,前边我们将切磋Binding的各类特点。

回头来看XAML代码,它选拔了Binding标记扩展语法:

1.3         Binding的源与途径

 

Binding
的源也便是数据的源流。Binding对源的须要并不苛刻——只要它是叁个指标,并且经过品质(Property)公开自个儿的多寡,它就能当做Binding
的源。

[html] view
plain
copyprint?

前面二个例子已经向大家表达,假诺想让作为Binding源的对象拥有自动公告Binding本人属性值已经已经成形的力量。那么就需求让类达成INotifyChanged接口并在性质的Set语句中激发PropertyChanged事件。在平日生活中,除了运用那种对象作为数据源之外,我们还有越来越多的选拔,比如控件把温馨的容器或子集成分当源、用一个控件做为另三个控件的数据源,把集同盟为ItemControl的数据源、使用XML作为TreeView或Menu的数据源。把四个控件关联到一个“数据制高点”上,甚至干脆不给Binding钦定数据源、让他自身去找。上边大家就分述那么些意况。

 

1.3.1       把控件作为Binding源与Binding标记扩展。

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  

前方讲过,半数以上意况下Binding的源是逻辑层对象,但有的时候为了让UI发生联合浮动作效果应也会动用Binding在控件间创设关联。下边包车型地铁代码是吧2个TextBox的Text属性关联到Slider的Value的性质上。

与之等价的C#代码是:

 

 

[html] view
plain
 copy

 

 

[csharp] view
plain
copyprint?

 print?

 

  1. <Window x:Class=”WpfApplication1.Window1″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window1″ Height=”321″ Width=”401″>  
  5.     <Grid>  
  6.         <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  
  7.         <Slider Height=”23″ HorizontalAlignment=”Left” Margin=”84,106,0,0″ Name=”slider1″ VerticalAlignment=”Top” Width=”212″ />  
  8.         <Button Content=”Button” Height=”23″ HorizontalAlignment=”Left” Margin=”166,197,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”75″ Click=”button1_Click” />  
  9.     </Grid>  
  10. </Window>  
  1. this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“Value”) { ElementName=”Slider1″});  

运维效果如下图:

因为Binding类的构造器自个儿有所能够吸收Path的参数,所以也常写作:

 

 

图片 6
正如大家所见,除了能够在C#中确立Binding外在XAML代码里也得以一本万利的设置Binding,那就给设计师相当大的自由度来支配UI成分之间的关联景况。值得注意的是,在C#代码中,能够访问在XAML中声称的变量不过XAML中不能访问C#中注脚的变量,因而,要想在XAML中树立UI成分和逻辑对象的Binding还要颇费些周折,把逻辑代码注脚为XAML中的财富(Resource),我们放能源一章去讲。

 

回头来看XAML代码,它使用了Binding标记扩张语法:

[html] view
plain
copyprint?

 

 

[html] view
plain
 copy

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Value,ElementName=slider1}”/>  

 

注意:

 print?

 

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  

因为大家在C#代码中能够直接待上访问控件对象,所以一般不会利用Binding的ElementName属性,而是直接赋值给Binding的Sourece属性。

与之等价的C#代码是:

Binding的标记扩充语法,初看有个别单调甚至有点别扭,但细品就会体会到其的精美之处。说它别扭,是因为大家已经习惯了Text=“Hello
World”那种键–值式的赋值方式,而且觉得值与品质的值类型一定要平等——-大脑不慢会质询Text=”{Binding
Value,ElementName=Slider1}”的字面意思—-Text的项目是String,为什么要赋三个Binding类型的值吗?其实我们并不是为Text属性赋值,为了消弭那种误解,大家得以把代码读作:为Text属性设置Binding为…。再想深一步,大家不是平日把函数视为1个值吗?只是那几个值在函数执行之后才能赢得。同理,大家也足以把Binding视为一种直接的、不固定的赋值情势—–Binding增加很适用的揭橥了这一个赋值情势。

 

1.3.2        控制Binding的可行性及数量更新

 

Binding在源与对象之间架起了联络的大桥,默许情状下数据即能够由此Binding送达目的,也足以通过指标回到源(收集用户对数据的改动)。有时候数据只必要体现给用户,不要求用户修改,那时候能够把Binding方式设置为从指标向源的单向关系以及只在Binding关系确马上读取3回数据,那亟需大家依照实际境况选取。

[csharp] view
plain
 copy

控制Binding数据流向的本性是Model,它的品类是BindingModel的枚举。BindingModel能够取值为TwoWay、OneWay、OneTime、OneWayToSource和Default。那里的Default指的是Binding的情势会依据指标是事实上处境来鲜明,比不上是足以编写的(TextBox的Text属性),Default就使用双向方式。要是是TextBlock,不可编辑,就应用单向方式。

 

接上一节的小例子,拖动Slider手柄时,TextBox就会显示Slider的当前值(实际上这一块提到到一个Double到String类型的变换,临时忽略不计);倘若大家在TextBox里面输入2个老少咸宜的值按Tab键、让难点离开TextBox,则Slider手柄就会跳转至相应的值那里。如下图所示:

 print?

图片 7

  1. this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“Value”) { ElementName=”Slider1″});  

干什么一定要在Text博克斯失去宗旨现在才转移值吗?那就引出了Binding的别的四个天性—–UpdateSourceTrigger,它的种类是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFous、Explicit和Default。显著,对于Text的Default行为与LostFocus一致,大家只供给把那一个值改成PropertyChanged,则Slider就会趁机输入值的转变而转变了。

因为Binding类的构造器自身具有能够接过Path的参数,所以也常写作:

注意:

 

顺手提一句,Binding还兼具NotifyOnSourceUpdated属性和NotifyOnTargetUpdated四个bool类型是性质。假如设置为True,则在源或指标被更新之后就会触发相应的SourceUpdated事件和TargetUpdated事件。实际工作中大家得以监听那八个事件来找出来怎样数据或控件被更新了。

 

1.3.3   Binding的路径(Path)

[html] view
plain
 copy

做为Binding的源恐怕会有不少属性,通过那个属性Binding源能够把数据揭穿给外界。那么,Binding到底要求关怀哪个属性值呢?就供给用Binding的Path属性来钦点了。例如前面这么些例子,我们把Slider控件对象作为数据源,把它的Value属性作为路径。

 

就算在XAML代码中依然Binding类的构造器参数列表中大家利用字符串来表示Path,但Path的实际上类型是PropertyPath。上面让大家来探视怎样创造Path来应付实际境况(作者将使用C#和XAML两种代码实行描述)。

 print?

最简便的章程正是一向把Binding关联到Binding源的性情上,前边的事例就是如此,语法如下:

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Value,ElementName=slider1}”/>  

 

注意:

[html] view
plain
copyprint?

 

 

因为大家在C#代码中得以直接待上访问控件对象,所以一般不会选用Binding的ElementName属性,而是径直赋值给Binding的Sourece属性。

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  

Binding的标记扩展语法,初看某个单调甚至某些别扭,但细品就会体会到其的精巧之处。说它别扭,是因为我们曾经见惯司空了Text=“Hello
World”那种键–值式的赋值情势,而且觉得值与质量的值类型一定要一如既往——-大脑极快会质询Text=”{Binding
Value,ElementName=Slider1}”的字面意思—-Text的门类是String,为何要赋三个Binding类型的值吗?其实大家并不是为Text属性赋值,为了排除那种误解,大家得以把代码读作:为Text属性设置Binding为…。再想深一步,大家不是平时把函数视为1个值吗?只是那几个值在函数执行之后才能拿到。同理,大家也得以把Binding视为一种直接的、不定点的赋值格局—–Binding扩张很确切的公布了这几个赋值格局。

等效的C#代码正是:

1.3.2        控制Binding的势头及数据更新

 

Binding在源与对象之内架起了关联的大桥,暗中同意情况下数据即能够通过Binding送达指标,也得以通过目的回到源(收集用户对数据的改动)。有时候数据只需求体现给用户,不需求用户修改,那时候能够把Binding格局设置为从指标向源的单向关系以及只在Binding关系确登时读取三次数据,那亟需大家依照实情采纳。

 

控制Binding数据流向的性质是Model,它的项目是BindingModel的枚举。BindingModel能够取值为TwoWay、OneWay、OneTime、OneWayToSource和Default。那里的Default指的是Binding的情势会依照指标是事实上意况来分明,不及是可以编写的(TextBox的Text属性),Default就选取双向形式。即便是TextBlock,不可编辑,就动用单向方式。

[csharp] view
plain
copyprint?

接上一节的小例子,拖动Slider手柄时,TextBox就会展现Slider的此时此刻值(实际上这一块提到到叁个Double到String类型的转换,一时半刻忽略不计);要是我们在TextBox里面输入七个确切的值按Tab键、让问题离开TextBox,则Slider手柄就会跳转至相应的值那里。如下图所示:

 

图片 8

  1. this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“Value”) {Source=slider1});  

何以一定要在TextBox失去主题今后才转移值吗?那就引出了Binding的其余1本特性—–UpdateSourceTrigger,它的品类是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFous、Explicit和Default。显明,对于Text的Default行为与LostFocus一致,我们只须要把这些值改成PropertyChanged,则Slider就会随着输入值的成形而转变了。

Binding还帮忙多元路径(通俗的讲便是一道“点”下去),比如,大家想让三个TextBox展现其余一个TextBox内容的尺寸,我们能够这么写:

注意:

 

顺便提一句,Binding还拥有NotifyOnSourceUpdated属性和NotifyOnTargetUpdated多少个bool类型是性质。如若设置为True,则在源或目的被更新之后就会接触相应的SourceUpdated事件和TargetUpdated事件。实际工作中我们能够监听那三个事件来找出来咋样数据或控件被更新了。

 

1.3.3   Binding的路径(Path)

[html] view
plain
copyprint?

做为Binding的源可能会有成都百货上千天性,通过这一个属性Binding源能够把多少暴光给外界。那么,Binding到底供给关爱哪个属性值呢?就需求用Binding的Path属性来钦点了。例如前面那一个事例,大家把Slider控件对象作为数据源,把它的Value属性作为路径。

 

固然在XAML代码中只怕Binding类的构造器参数列表中大家应用字符串来代表Path,但Path的实际类型是PropertyPath。上边让大家来探望哪些创建Path来敷衍实情(作者将使用C#和XAML三种代码进行描述)。

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,50,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”158″ />  
  2.        <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,105,0,0″ Name=”textBox2″ Text=”{Binding Path=Text.Length,ElementName=textBox1,Mode=OneWay}” VerticalAlignment=”Top” Width=”158″/>  

最简单易行的主意便是直接把Binding关联到Binding源的特性上,后面包车型地铁例证正是这么,语法如下:

等效的C#代码是:

 

 

[html] view
plain
 copy

 

 

[csharp] view
plain
copyprint?

 print?

 

  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”141,46,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”120″ Text=”{Binding Path=Value,ElementName=slider1}”/>  
  1. this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“Text.Length”) {Source = textBox1, Mode= BindingMode.OneWay });  

等效的C#代码正是:

运行效果如下图:

 

 

 

图片 9
大家理解,集合类型是索引器(Indexer)又称作带参属性。既然是性质,索引器也能看做Path来选用。比如大家想让多个Text博克斯展现其余3个TextBox的第伍个字符,大家能够这么写:

[csharp] view
plain
 copy

 

 

[html] view
plain
copyprint?

 print?

 

  1. this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“Value”) {Source=slider1});  
  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,50,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”158″ Text=”ABCDE” />  
  2.        <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,105,0,0″ Name=”textBox2″ Text=”{Binding Path=Text[3],ElementName=textBox1,Mode=OneWay}” VerticalAlignment=”Top” Width=”158″/>  

Binding还匡助多元路径(通俗的讲正是手拉手“点”下去),比如,我们想让1个TextBox彰显别的三个TextBox内容的长短,大家得以这样写:

C#代码如下:

 

 

 

 

[html] view
plain
 copy

[csharp] view
plain
copyprint?

 

 

 print?

  1. this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“Text.[3]”) { Source=textBox1,Mode= BindingMode.OneWay});  
  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,50,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”158″ />  
  2.        <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,105,0,0″ Name=”textBox2″ Text=”{Binding Path=Text.Length,ElementName=textBox1,Mode=OneWay}” VerticalAlignment=”Top” Width=”158″/>  

咱俩竟然可以把Text与[3]里面的点去掉,一样能够正确工作,运维效果如下图:

等效的C#代码是:

 

 

图片 10
当使用3个晤面也许DataView做为数据源时,假设我们想把它私下认可的因素做为数据源使用,则供给使用上面包车型大巴语法:

 

 

[csharp] view
plain
 copy

[csharp] view
plain
copyprint?

 

 

 print?

  1. List<string> infos = new List<string>() { “Jim”,”Darren”,”Jacky”};  
  2.            textBox1.SetBinding(TextBox.TextProperty, new Binding(“/”) { Source=infos});  
  3.            textBox2.SetBinding(TextBox.TextProperty, new Binding(“/[2]”) { Source = infos, Mode= BindingMode.OneWay });  
  4.            textBox3.SetBinding(TextBox.TextProperty, new Binding(“/Length”) { Source = infos, Mode= BindingMode.OneWay });  
  1. this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“Text.Length”) {Source = textBox1, Mode= BindingMode.OneWay });  

展现效果如下:

运维效果如下图:

 

 

图片 11

图片 12
大家知晓,集合类型是索引器(Indexer)又称为带参属性。既然是性质,索引器也能看做Path来行使。比如大家想让七个TextBox展现其它一个TextBox的第5个字符,我们能够那样写:

即便集合中还是是相会,大家想把子集集合中的成分做Path,大家得以应用多级斜线的语法(即“一路”斜线下去),例如:

 

 

[html] view
plain
 copy

[html] view
plain
copyprint?

 

 

 print?

  1. /// <summary>  
  2.    /// Window4.xaml 的相互逻辑  
  3.    /// </summary>  
  4.    public partial class Window4 : Window  
  5.    {  
  6.        public Window4()  
  7.        {  
  8.            InitializeComponent();  
  9.            List<Contry> infos = new List<Contry>() { new Contry() { Name = “中国”, Provinces= new List<Province>(){ new Province(){ Name=”四川”,Citys=new List<City>(){new  City(){Name=”绵阳市”  
  10.            }}}}}};  
  11.            this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“/Name”) { Source=infos});  
  12.            this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“/Provinces/Name”) { Source = infos });  
  13.            this.textBox3.SetBinding(TextBox.TextProperty, new Binding(“/Provinces/Citys/Name”) { Source = infos });  
  14.        }  
  15.    }  
  16.   
  17.     class City  
  18.    {  
  19.        public string Name { set; get; }  
  20.    }  
  21.   
  22.    class Province  
  23.    {  
  24.        public string Name { set; get; }  
  25.        public List<City> Citys { set; get; }  
  26.    }  
  27.   
  28.    class Contry  
  29.    {  
  30.        public string Name { set; get; }  
  31.        public List<Province> Provinces { get; set; }  
  32.    }  
  1. <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,50,0,0″ Name=”textBox1″ VerticalAlignment=”Top” Width=”158″ Text=”ABCDE” />  
  2.        <TextBox Height=”23″ HorizontalAlignment=”Left” Margin=”152,105,0,0″ Name=”textBox2″ Text=”{Binding Path=Text[3],ElementName=textBox1,Mode=OneWay}” VerticalAlignment=”Top” Width=”158″/>  

运维效果如图:

C#代码如下:

 

 

图片 13

 

1.3.4       “没有Path”的Binding

[csharp] view
plain
 copy

有的时候我们会在代码中大家看大Path是3个“.”或然差不离没有Path的Binding,着实令人摸不着头脑。原来那是一种相比较奇特的情形—Binding源本人就是一种多少且不须求Path来指明。典型的string,int等中央项目都是那般,他们是实例本身就是数量,大家不可能钦赐通过充足属性来拜访那一个数目,那是大家只供给将以此数据设置为.就足以了。在XAML中那一个.能够忽略不写,可是在C#中编制程序必须求带上。上边请看上边那段代码:

 

 

 print?

[html] view
plain
copyprint?

  1. this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“Text.[3]”) { Source=textBox1,Mode= BindingMode.OneWay});  

 

咱俩照旧足以把Text与[3]以内的点去掉,一样能够正确工作,运营效果如下图:

  1. <Window x:Class=”WpfApplication1.Window5″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:String=”clr-namespace:System;assembly=mscorlib”  
  5.         Title=”Window5″ Height=”331″ Width=”538″>  
  6.     <StackPanel Height=”184″ Name=”stackPanel1″ Width=”288″>  
  7.         <StackPanel.Resources>  
  8.             <String:String x:Key=”myString”>  
  9.                 菩提本无树,何处染纤尘。  
  10.             </String:String>  
  11.               
  12.         </StackPanel.Resources>  
  13.         <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding Path=.,Source={StaticResource ResourceKey=myString}}” />  
  14.     </StackPanel>  
  15. </Window>  

 

上面的代码能够简写成:

图片 14
当使用二个会晤或许DataView做为数据源时,假设大家想把它暗中认可的要素做为数据源使用,则供给利用上边包车型客车语法:

 

 

 

[csharp] view
plain
 copy

[html] view
plain
copyprint?

 

 

 print?

  1. <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding .,Source={StaticResource ResourceKey=myString}}” />  
  1. List<string> infos = new List<string>() { “Jim”,”Darren”,”Jacky”};  
  2.            textBox1.SetBinding(TextBox.TextProperty, new Binding(“/”) { Source=infos});  
  3.            textBox2.SetBinding(TextBox.TextProperty, new Binding(“/[2]”) { Source = infos, Mode= BindingMode.OneWay });  
  4.            textBox3.SetBinding(TextBox.TextProperty, new Binding(“/Length”) { Source = infos, Mode= BindingMode.OneWay });  

或许直接写成:

体现效果如下:

 

 

 

图片 15

[html] view
plain
copyprint?

万一集合中依旧是集结,大家想把子集集合中的成分做Path,大家能够动用多级斜线的语法(即“一路”斜线下去),例如:

 

 

  1. <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding Source={StaticResource ResourceKey=myString}}” />  

[html] view
plain
 copy

 

 

注意:

 print?

说到底这种简写很简单被误解为没有点名Path,其实只是省略掉了。与只等效的C#代码如下:

  1. /// <summary>  
  2.    /// Window4.xaml 的相互逻辑  
  3.    /// </summary>  
  4.    public partial class Window4 : Window  
  5.    {  
  6.        public Window4()  
  7.        {  
  8.            InitializeComponent();  
  9.            List<Contry> infos = new List<Contry>() { new Contry() { Name = “中国”, Provinces= new List<Province>(){ new Province(){ Name=”四川”,Citys=new List<City>(){new  City(){Name=”绵阳市”  
  10.            }}}}}};  
  11.            this.textBox1.SetBinding(TextBox.TextProperty, new Binding(“/Name”) { Source=infos});  
  12.            this.textBox2.SetBinding(TextBox.TextProperty, new Binding(“/Provinces/Name”) { Source = infos });  
  13.            this.textBox3.SetBinding(TextBox.TextProperty, new Binding(“/Provinces/Citys/Name”) { Source = infos });  
  14.        }  
  15.    }  
  16.   
  17.     class City  
  18.    {  
  19.        public string Name { set; get; }  
  20.    }  
  21.   
  22.    class Province  
  23.    {  
  24.        public string Name { set; get; }  
  25.        public List<City> Citys { set; get; }  
  26.    }  
  27.   
  28.    class Contry  
  29.    {  
  30.        public string Name { set; get; }  
  31.        public List<Province> Provinces { get; set; }  
  32.    }  

 

运转效果如图:

[csharp] view
plain
copyprint?

 

 

图片 16

  1. string myString = “菩提本无树,明镜亦无台。本来无一物,何处染纤尘。”;  
  2.            this.textBlock1.SetBinding(TextBlock.TextProperty, new Binding(“.”) { Source=myString});  

1.3.4       “没有Path”的Binding

注意:

某些时候大家会在代码中我们看大Path是二个“.”可能索性没有Path的Binding,着实令人摸不着头脑。原来这是一种比较特出的气象—Binding源本人便是一种多少且不要求Path来指明。典型的string,int等为主项目都以这么,他们是实例本身就是数额,大家鞭长莫及钦点通过丰盛属性来走访这么些数据,那是我们只必要将这一个数量设置为.就足以了。在XAML中那些.能够忽略不写,但是在C#中编程必供给带上。上面请看下边那段代码:

 

 

末段顺便带一句,PropertyPath除了用于Binding的帕特h属性之外,在动画编制程序的时候也会派上用场(Storyboard.TargetProperty)。在用来动画编程的时候,PropertyPath还有别的一种语法,到时候大家细说。

[html] view
plain
 copy

1.3.5      把Binding钦点为源(Source)的三种格局

 

上一节大家学习了什么通过Binding的path属性怎样在1个目的上搜索数据。这一节咱们将学习如何为Binding钦赐源(Source)。

 print?

Binding的源是数据的来源于,所以,只要1个目的涵盖数据同时能够因此性能将数据暴流露来,它就能当作Binding的源来使用。包涵数据的指标俯拾即是,但无法不为Binding的Source钦定合适的对象Binding才能不奇怪工作,常用的措施有:

  1. <Window x:Class=”WpfApplication1.Window5″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:String=”clr-namespace:System;assembly=mscorlib”  
  5.         Title=”Window5″ Height=”331″ Width=”538″>  
  6.     <StackPanel Height=”184″ Name=”stackPanel1″ Width=”288″>  
  7.         <StackPanel.Resources>  
  8.             <String:String x:Key=”myString”>  
  9.                 菩提本无树,何处染纤尘。  
  10.             </String:String>  
  11.               
  12.         </StackPanel.Resources>  
  13.         <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding Path=.,Source={StaticResource ResourceKey=myString}}” />  
  14.     </StackPanel>  
  15. </Window>  

 

地点的代码能够简写成:

  • 把一般的CL汉兰达单个对象钦赐为Source:包蕴.NetFrameWork自带类型的靶子和用户自定义类型的靶子。假如类型完结了INotifyPropertyChanged接口,那足以通过在性质的Set语句里激发PropertyChanged事件来布告Binding已经更新。
  • 把通常的CL兰德CRUISER对象集合钦点为Source:包含数组,List<T>,ObservableCollection<T>等联谊类型。实际工作中,大家平时索要将2个凑合类型作为ItemControl的派生类的数额来行使,一般把控件ItemSource属性使用Binding关联到叁个会合对象上。
  • 把ADO.NET数据钦点为Source:包蕴DataTable和DataView对象。
  • 选择XmlDataProvider把XML数据钦命为Source:XML做为标准的数量传输和储存格式,差不离无处不在,大家得以用它象征单个对象可能聚众对象;一些WPF控件是级联的(如Treeview和Menu),我们得以把树状结构的XML数据作为源钦定给与之提到的Binding。
  • 把依赖对象(Dependency
    Object)钦点为Source:注重对象不仅能够做为Binding
    的对象,还是能看做Binding
    的源。那样就有或者形成Binding链。信赖对象中的正视属性能够做为Binding的Path。
  • 把容器的DataContext钦定为Source(WPF
    中Binding的暗中同意行为):有时候大家会遇见那样一种情况—-大家肯定知道将从10分属性获取数据,但现进行使哪个目标作为Binding的源还不明确。那时候大家只须求先创造五个Binding,只给它设置Path而不设置Source,让这几个Binding本人去搜寻源,那时候,Binding会自动把控件的DataContext作为当作本人的Source(它会沿着控件树一直向外找,直到找到带有Path内定的目的甘休)。
  • 通过ElementName指定Source:在C#代码中得以平昔把目的作为Source赋值给Binding,可是XAML不能够访问对象,只能动用Name属性来找到对象。
  • 通过Binding的RelataveSource属性相对的钦点Source:当控件须要关爱自身的、自身容器的可能自个儿内部某些属性值就必要利用那种方法。
  • 把ObjectDataProvider内定为Source:当数据源的数据不是通过质量,而是通过措施行强揭穿给外界的时候,咱们得以应用那种对象来包装数据源再把它们钦点为Source。
  • 把施用LINQ检索到的多少作为数据源。

 

 

 

下边大家利用实例来分别讲述各个状态:

[html] view
plain
 copy

1.3.6       没有Source的Binding—-使用DataContext作为数据源

 

前方的事例都是把单个的CLPRADO对象作为Binding
的源,方法有三种:把对象赋值给Binding.Source属性也许把目的的Name赋值给Binding.ElementName。DataContext被定义在FrameWorkElement类中,那些类是WPF控件的基类,那意味全体的WPF控件包含布局控件都包涵那天天性。如前所述,WPF的UI布局是树形结构,那一个树的每一种节点都以控件,由此大家生产叁个结论—-在UI树的种种节点都有DataContext属性。那点万分首要,因为当贰个Binding只驾驭自身的Path而不知底自身的源的时候,它会沿着树的联合署名向树的根部找过去,每经过3个节点都要查看那些节点的DataContext属性是还是不是具备Path所钦定的质量。借使有,就把那几个指标作为自个儿的Source;假如没有,就继续找下去;假使到树的根部还尚未找到,那那一个Binding就不曾Source,因此也不会收获数码,让大家看看下边包车型大巴事例:

 print?

先成立贰个名为Student的类,它装有ID,Name,Age2个天性:

  1. <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding .,Source={StaticResource ResourceKey=myString}}” />  

 

只怕直接写成:

[csharp] view
plain
copyprint?

 

 

 

  1. public class Student  
  2.     {  
  3.         public int Id { get; set; }  
  4.         public string Name { get; set; }  
  5.         public int Age { get; set; }  
  6.     }  

[html] view
plain
 copy

在后在XAML中建立UI界面:

 

 

 print?

 

  1. <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding Source={StaticResource ResourceKey=myString}}” />  

[html] view
plain
copyprint?

 

 

注意:

  1. <Window x:Class=”WpfApplication1.Window6″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:Stu=”clr-namespace:WpfApplication1″  
  5.         Title=”Window6″ Height=”345″ Width=”464″>  
  6.     <StackPanel Background=”AliceBlue”>  
  7.         <StackPanel.DataContext>  
  8.             <Stu:Student Id=”1″ Name=”Darren” Age=”10″></Stu:Student>  
  9.         </StackPanel.DataContext>  
  10.         <Grid>  
  11.             <StackPanel Height=”283″ HorizontalAlignment=”Left” Margin=”12,12,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”418″>  
  12.                 <TextBox Height=”23″ Name=”textBox1″ Width=”120″ Margin=”15″ Text=”{Binding Path=Id}”/>  
  13.                 <TextBox Height=”23″ Name=”textBox2″ Width=”120″ Margin=”15″ Text=”{Binding Path=Name}”/>  
  14.                 <TextBox Height=”23″ Name=”textBox3″ Width=”120″ Margin=”15″ Text=”{Binding Path=Age}”/>  
  15.             </StackPanel>  
  16.         </Grid>  
  17.     </StackPanel>  
  18.       
  19. </Window>  

最终那种简写很不难被误会为没有点名帕特h,其实只是省略掉了。与只等效的C#代码如下:

其一UI能够用如下的柱状图来表示:

 

 

[csharp] view
plain
 copy

**图片 17

 

**

 print?

运用xmlns:Stu=”clr-namespace:WpfApplication1″,咱们就足以在XAML中央银行使在C#中定义的类。使用了这几行代码:

  1. string myString = “菩提本无树,明镜亦无台。本来无一物,何处染纤尘。”;  
  2.            this.textBlock1.SetBinding(TextBlock.TextProperty, new Binding(“.”) { Source=myString});  

 

注意:

[html] view
plain
copyprint?

 

 

末尾顺便带一句,PropertyPath除了用于Binding的Path属性之外,在动画编制程序的时候也会派上用场(Storyboard.TargetProperty)。在用于动画编制程序的时候,Property帕特h还有其余一种语法,到时候大家细说。

  1. <StackPanel.DataContext>  
  2.            <Stu:Student Id=”1″ Name=”Darren” Age=”10″></Stu:Student>  
  3.        </StackPanel.DataContext>  

1.3.5      把Binding内定为源(Source)的二种格局

就为外层StackPanel的DataContext实行了赋值—-它是叁个Student对象。1个TextBox通过Binding获取值,但只为Binding钦命了Path,没有点名Source。简写成这么也得以:

上一节大家上学了怎样通过Binding的path属性如何在一个对象上摸索数据。这一节我们将学习怎样为Binding钦点源(Source)。

 

Binding的源是数额的来自,所以,只要八个目的涵盖数据同时能够由此质量将数据暴揭发来,它就能当作Binding的源来使用。包蕴数据的指标如拾草芥,但必须为Binding的Source钦点合适的对象Binding才能健康干活,常用的点子有:

 

 

[html] view
plain
copyprint?

  • 把平时的CL途乐单个对象钦赐为Source:包涵.NetFrameWork自带类型的靶子和用户自定义类型的对象。若是类型完成了INotifyPropertyChanged接口,那足以经过在性质的Set语句里激发PropertyChanged事件来通告Binding已经更新。
  • 把普通的CL本田UR-V对象集合钦赐为Source:包罗数组,List<T>,ObservableCollection<T>等联谊类型。实际工作中,大家平时索要将二个成团类型作为ItemControl的派生类的数据来使用,一般把控件ItemSource属性使用Binding关联到1个凑合对象上。
  • 把ADO.NET数据钦命为Source:包含DataTable和DataView对象。
  • 应用XmlDataProvider把XML数据钦点为Source:XML做为标准的数额传输和仓库储存格式,大概无处不在,大家得以用它意味着单个对象大概聚众对象;一些WPF控件是级联的(如Treeview和Menu),大家得以把树状结构的XML数据作为源钦命给与之提到的Binding。
  • 把注重对象(Dependency
    Object)内定为Source:依赖对象不仅能够做为Binding
    的靶子,还能够当做Binding
    的源。那样就有恐怕形成Binding链。注重对象中的重视属性能够做为Binding的Path。
  • 把容器的DataContext钦赐为Source(WPF
    中Binding的暗中认可行为):有时候大家会碰到这么一种情形—-大家鲜明通晓将从12分属性获取数据,但实际运用哪个指标作为Binding的源还不鲜明。那时候我们只须求先创立2个Binding,只给它设置Path而不设置Source,让那个Binding自个儿去找寻源,那时候,Binding会自动把控件的DataContext作为当作自身的Source(它会顺着控件树平昔向外找,直到找到带有帕特h钦赐的对象结束)。
  • 通过ElementName指定Source:在C#代码中得以直接把对象作为Source赋值给Binding,不过XAML不可能访问对象,只好使用Name属性来找到对象。
  • 经过Binding的RelataveSource属性相对的钦赐Source:当控件必要关爱本人的、自身容器的要么自身之中有些属性值就要求运用那种措施。
  • 把ObjectDataProvider钦命为Source:当数据源的数量不是通过质量,而是通过艺术暴光给外界的时候,大家得以应用那种对象来包装数据源再把它们钦点为Source。
  • 把施用LINQ检索到的多寡作为数据源。

 

 

  1. <TextBox Height=”23″ Name=”textBox1″ Width=”120″ Margin=”15″ Text=”{Binding Id}”/>  
  2.                 <TextBox Height=”23″ Name=”textBox2″ Width=”120″ Margin=”15″ Text=”{Binding Name}”/>  
  3.                 <TextBox Height=”23″ Name=”textBox3″ Width=”120″ Margin=”15″ Text=”{Binding Age}”/>  

上面我们运用实例来分别讲述各类情景:

这么二个TextBox就会沿着树向上搜索可用的DataContext对象。运营效果如下图:

1.3.6       没有Source的Binding—-使用DataContext作为数据源

 

前方的事例都以把单个的CL兰德酷路泽对象作为Binding
的源,方法有两种:把目的赋值给Binding.Source属性或许把目的的Name赋值给Binding.ElementName。DataContext被定义在FrameWorkElement类中,这些类是WPF控件的基类,那意味全部的WPF控件包蕴布局控件都含有那个性情。如前所述,WPF的UI布局是树形结构,那一个树的各个节点都以控件,因此大家生产贰个结论—-在UI树的种种节点都有DataContext属性。那一点至极首要,因为当三个Binding只领悟自身的Path而不知情本人的源的时候,它会沿着树的一块向树的根部找过去,每经过三个节点都要查看那个节点的DataContext属性是还是不是享有Path所钦赐的质量。假设有,就把那一个指标作为自身的Source;假若没有,就继续找下去;假诺到树的根部还未曾找到,那这么些Binding就不曾Source,因此也不会得到数码,让大家看看上边包车型大巴事例:

图片 18

先创立3个名为Student的类,它富有ID,Name,Age1天性格:

前边在学习Binding路径的时候,当Binding的Source本身正是多少、不供给选用品质来暴光数据时,Binding的Path能够安装为”.”,亦可省略不写。现在Source也得以不难不写了,那样,当有些DataContext为简便类型对象的时候,大家完全或然看到3个既没有Path,又从未Source的Binding:

 

 

[csharp] view
plain
 copy

[html] view
plain
copyprint?

 

 

 print?

  1. <Window x:Class=”WpfApplication1.Window7″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:Str=”clr-namespace:System;assembly=mscorlib”  
  5.         Title=”Window7″ Height=”300″ Width=”300″>  
  6.     <Grid>  
  7.         <Grid.DataContext>  
  8.             <Str:String>Hello DataContext</Str:String>  
  9.         </Grid.DataContext>  
  10.         <StackPanel>  
  11.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock1″ Text=”{Binding}” VerticalAlignment=”Top” />  
  12.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock2″ Text=”{Binding}” VerticalAlignment=”Top” />  
  13.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock3″ Text=”{Binding}” VerticalAlignment=”Top” />  
  14.         </StackPanel>  
  15.           
  16.     </Grid>  
  17. </Window>  
  1. public class Student  
  2.     {  
  3.         public int Id { get; set; }  
  4.         public string Name { get; set; }  
  5.         public int Age { get; set; }  
  6.     }  

运作效果如下图:

在后在XAML中建立UI界面:

 

 

图片 19

 

你只怕回顾,Binding怎么会自动向UI元素上一层查找DataContext并把它看作团结的Source呢?其实,“Binding沿着UI成分树向上找”只是WPF给大家的二个错觉,Binding并没有那么智能。之所以会这么是因为DataContext是三个“依赖属性”,前边的章节大家会详细描述,注重属性有1个很分明的特性正是您未曾为有些控件的依赖属性赋值的时候,控件会把温馨容器的属性值接过来当作本人的属性值。实际上属性值是本着UI成分树向下传递的。

[html] view
plain
 copy

在事实上工作中,DataContext属性值的选择格外的灵巧。比如:

 

当UI上的八个控件都采取Binding关心同三个对象变化的时候,无妨选择DataContext。

 print?

当作为Source的目的无法被直接待上访问的时候—-比如B窗体内的控件想把A窗体里的控件当作自身的Binding源时,可是A窗体内的控件可访问级别是private类型,那是就足以把这么些控件恐怕控件值作为窗体A的DataContext(这么些本性是Public级其余)那样就能够揭穿数据了。

  1. <Window x:Class=”WpfApplication1.Window6″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:Stu=”clr-namespace:WpfApplication1″  
  5.         Title=”Window6″ Height=”345″ Width=”464″>  
  6.     <StackPanel Background=”AliceBlue”>  
  7.         <StackPanel.DataContext>  
  8.             <Stu:Student Id=”1″ Name=”Darren” Age=”10″></Stu:Student>  
  9.         </StackPanel.DataContext>  
  10.         <Grid>  
  11.             <StackPanel Height=”283″ HorizontalAlignment=”Left” Margin=”12,12,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”418″>  
  12.                 <TextBox Height=”23″ Name=”textBox1″ Width=”120″ Margin=”15″ Text=”{Binding Path=Id}”/>  
  13.                 <TextBox Height=”23″ Name=”textBox2″ Width=”120″ Margin=”15″ Text=”{Binding Path=Name}”/>  
  14.                 <TextBox Height=”23″ Name=”textBox3″ Width=”120″ Margin=”15″ Text=”{Binding Path=Age}”/>  
  15.             </StackPanel>  
  16.         </Grid>  
  17.     </StackPanel>  
  18.       
  19. </Window>  

印象的说,那时候外层的数额就也就是一个数码的“至高点”,只要把成分放上去,旁人就可见看见。其它DataContext自个儿就是一个借助属性,大家得以选取Binding把它事关到3个数量源上。

本条UI能够用如下的柱状图来代表:

1.3.7     使用集合对象作为列表控件的ItemsSource

 

有了DataContext作为基础,大家再来看看把集合类型对象作为Binding源的动静。

**图片 20

WPF中的列表式控件都派生自ItemControl类,自然也三番陆回了ItemSource那几个天性。ItemSource能够选择3个IEnumerable接口派生类的实例作为友好的值(全部可被迭代遍历的会师都完毕了那一个接口,包含数组、List<T>等)。每一个ItemControl都有着友好的条规容器Item
Container,例如,ListBox的条规容器是ListBoxItem、Combox的条文容器是ComboxItem。ItemSource里面保存的是一条一条的多寡,想要把数量呈现出来就要为数量穿上海外国语大学衣,条目容器就起到了数码外衣的职能。那样将数据外衣和它所对应的条文容器关联起来呢?当然时依靠Binding!只要大家为二个ItemControl设置了ItemSource属性值,ItemControl会自行迭代个中的多少成分,为各种数据成分准备三个条目容器,并应用Binding成分在条款容器和数码成分之间创立起涉及,让大家来看二个例证:

**

UI代码如下:

选择xmlns:Stu=”clr-namespace:WpfApplication1″,大家就足以在XAML中运用在C#中定义的类。使用了这几行代码:

 

 

[html] view
plain
copyprint?

[html] view
plain
 copy

 

 

  1. <Window x:Class=”WpfApplication1.Window8″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window8″ Height=”356″ Width=”471″>  
  5.     <Grid>  
  6.         <StackPanel Height=”295″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”427″>  
  7.             <TextBlock Height=”23″ Name=”textBlock1″ Text=”学员编号:” />  
  8.             <TextBox Height=”23″ Name=”txtStudentId” Width=”301″ HorizontalAlignment=”Left”/>  
  9.             <TextBlock Height=”23″ Name=”textBlock2″ Text=”学员列表:” />  
  10.             <ListBox Height=”208″ Name=”lbStudent” Width=”305″ HorizontalAlignment=”Left”/>  
  11.         </StackPanel>  
  12.     </Grid>  
  13. </Window>  

 print?

 

  1. <StackPanel.DataContext>  
  2.            <Stu:Student Id=”1″ Name=”Darren” Age=”10″></Stu:Student>  
  3.        </StackPanel.DataContext>  

窗体运营效果如下图:

就为外层StackPanel的DataContext实行了赋值—-它是一个Student对象。1个TextBox通过Binding获取值,但只为Binding钦定了Path,没有点名Source。简写成那样也能够:

图片 21

 

咱俩要完结的效应正是把List<Student>的汇集作为ListBox的ItemSource,让ListBox呈现学员的Name,并行使TextBox显示当前选中学员的Id,为了落到实处这几个效能,大家必要在窗体的构造函数中添加几行代码:

 

 

[html] view
plain
 copy

[csharp] view
plain
copyprint?

 

 

 print?

  1. List<Student> infos = new List<Student>() {   
  2.             new Student(){ Id=1, Age=11, Name=”Tom”},  
  3.             new Student(){ Id=2, Age=12, Name=”Darren”},  
  4.             new Student(){ Id=3, Age=13, Name=”Jacky”},  
  5.             new Student(){ Id=4, Age=14, Name=”Andy”}  
  6.             };  
  7.             this.lbStudent.ItemsSource = infos;  
  8.             this.lbStudent.DisplayMemberPath = “Name”;  
  9.   
  10.             this.txtStudentId.SetBinding(TextBox.TextProperty,new Binding(“SelectedItem.Id”){ Source=lbStudent});  
  1. <TextBox Height=”23″ Name=”textBox1″ Width=”120″ Margin=”15″ Text=”{Binding Id}”/>  
  2.                 <TextBox Height=”23″ Name=”textBox2″ Width=”120″ Margin=”15″ Text=”{Binding Name}”/>  
  3.                 <TextBox Height=”23″ Name=”textBox3″ Width=”120″ Margin=”15″ Text=”{Binding Age}”/>  

运作结果如下图:

那般1个TextBox就会沿着树向上查找可用的DataContext对象。运营效果如下图:

 

 

**图片 22

图片 23

您或者回想,这一个事例中并不曾出现刚才大家说的Binding。实际上, this.lbStudent.DisplayMemberPath

“Name”;这一点代码揭破了几许一望可知。注意到含有Path那一个单词了吧?这阐明它是3个途径。当DisplayMemberPath
被赋值未来,ListBox在获得ItemSource的时候就会创制二个等量的ListBoxItem并以DisplayMemberPath的值为Path创设Binding,Binding的靶子是ListBoxItem的内容插件(实际上是三个TextBox,下边就会看见)。**

如过在ItemControl类的代码里刨根问底,你会发觉Binding的历程是在DisplayMemberTemplateSelector类的SelectTemplate方法里完结的。那些措施的定义格式如下:

 

[csharp] view
plain
copyprint?

 

  1. public override DataTemplate SelectTemplate(object item, DependencyObject container)  
  2.         {  
  3.             //逻辑代码  
  4.         }  

此地大家倒不用关心它的实际内容,注意到它的重回值没有,是1个DataTemplate类型的值。数据的门面正是由DataTemplate穿上的!当大家没有为ItemControl突显的钦命Template的时候SelectTemplate会默许的为大家成立2个最简便易行的DataTemplate—-就接近给多少穿上了1个简易的服装一样。至于哪些是Template以及这些主意的总体代码将会安放与Template相关的文章中仔细去探讨。那里我们只关注SelectTemplate内部创设Binding
的几行首要代码:

 

 

[csharp] view
plain
copyprint?

 

  1. FrameworkElementFactory text = ContentPresenter.CreateTextBlockFactory();  
  2.            Binding bind = new Binding();  
  3.            bind.Path = new PropertyPath(_displayMemberPath);  
  4.            bind.StringFormat = _stringFormat;  
  5.            text.SetBinding(TextBlock.TextProperty,bind);  

注意:

 

此间对新创建的Binding设定了Path而尚未点名Source,紧接那就把它涉及到了TextBlock上。明显,要想取得Source,那几个Binding要求向树根方向搜索包蕴_displayMemberPath钦定属性的DataContext。

前边在读书Binding路径的时候,当Binding的Source本人就是数据、不必要采用质量来揭露数据时,Binding的Path能够安装为”.”,亦可省略不写。未来Source也得以总结不写了,那样,当有个别DataContext为简便类型对象的时候,大家一齐大概看到四个既没有Path,又没有Source的Binding:

**最后大家再看一个出示为数据设置DataTemplate的例证,先把C#代码中的this.lbStudent.DisplayMemberPath

“Name”;一句删除,再在XAML代码中拉长几行代码,ListBox的ItemTemplate属性(继承自ItemControl类)的体系是DataTemplate,下边大家就为Student类型实例量身定做“服装”。**

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window8″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window8″ Height=”356″ Width=”471″>  
  5.     <Grid>  
  6.         <StackPanel Height=”295″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”427″>  
  7.             <TextBlock Height=”23″ Name=”textBlock1″ Text=”学员编号:” />  
  8.             <TextBox Height=”23″ Name=”txtStudentId” Width=”301″ HorizontalAlignment=”Left”/>  
  9.             <TextBlock Height=”23″ Name=”textBlock2″ Text=”学员列表:” />  
  10.             <ListBox Height=”208″ Name=”lbStudent” Width=”305″ HorizontalAlignment=”Left”>  
  11.                 <ListBox.ItemTemplate>  
  12.                     <DataTemplate>  
  13.                         <StackPanel Name=”stackPanel2″ Orientation=”Horizontal”>  
  14.                             <TextBlock  Text=”{Binding Id}” Margin=”5″ Background=”Beige”/>  
  15.                             <TextBlock Text=”{Binding Name}” Margin=”5″/>  
  16.                             <TextBlock  Text=”{Binding Age}” Margin=”5″/>  
  17.                         </StackPanel>  
  18.                     </DataTemplate>  
  19.                 </ListBox.ItemTemplate>  
  20.             </ListBox>  
  21.               
  22.         </StackPanel>  
  23.     </Grid>  
  24. </Window>  

运维效果图:

 

图片 24

说到底尤其提醒我们一点:

在采纳集合类型的多少作为列表控件的ItemSource时一般会考虑采纳ObservableCollection<T>替换List<T>,因为ObservableCollection<T>类完结了INotifyChange和INotifyPropertyChanged接口,能把集合的变化及时通告展现到它的列表控件上,改变会立即突显出来。

 

1.3.8     使用ADO.NET对象作为Binding的源

在.Net开发工作中,我们用ADO.NET类对数据库举办操作。常见的做事便是从数据库中读取数据到DataTable中,在把DataTable里的数据绑定的UI的控件里面(如成绩单、博客列表)。即使在风行的软件架构中并不把DataTable中的数据直接呈今后UI列表控件里面而是先经过LINQ等伎俩把DataTable里的数额转换来稳妥的用户自定义类型集合,但WPF也支撑DataTable也支撑在列表控件和DataTable里间接建立Binding。

今后大家做三个实例来讲学如何在DataTable和UI建立Binding:

大部状态下大家会用ListView控件来呈现一个DataTable,XAML代码如下:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window9″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window9″ Height=”345″ Width=”482″>  
  5.     <StackPanel Height=”279″ Name=”stackPanel1″ Width=”431″>  
  6.         <ListView Height=”247″ Name=”listView1″ Width=”376″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                      
  10.                         <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding Id}” Width=”60″>  
  11.                               
  12.                         </GridViewColumn>  
  13.                         <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding Name}” Width=”60″>  
  14.   
  15.                         </GridViewColumn>  
  16.                         <GridViewColumn Header=”Age” DisplayMemberBinding=”{Binding Age}” Width=”60″>  
  17.   
  18.                         </GridViewColumn>  
  19.                         <GridViewColumn Header=”Sex” DisplayMemberBinding=”{Binding Sex}” Width=”60″>  
  20.   
  21.                         </GridViewColumn>  
  22.                       
  23.                 </GridView>  
  24.             </ListView.View>  
  25.         </ListView>  
  26.     </StackPanel>  
  27. </Window>  

此地我们有几点必要留意的地方:

 

从字面上来领悟,ListView和GridView应该属于同一流其他控件,实际上并未这么!ListView是ListBox的派生类而GridView是ViewBase的派生类,ListView中的View是2个ViewBase对象,所以,GridView能够做为ListView的View来使用而不可能当做独立的控件来使用。这里运用理念是构成形式,即ListView有三个View,不过关于是GridView依然别的体系的View,由程序员自个儿选用—-近日唯有三个GridView可用,推测微软在此地还会有恢宏。其次,GridView的内容属性是Columns,那性子子是GridViewColumnCollection类型对象。因为XAML援助对情节属性的简写,能够简单<GridView.Columns>那层标签,间接在GridView的内容部分概念2个<GridViewColumn>对象,GridViewColumn中最根本的叁本性情是DisplayBinding(类型是BindingBase),使用这么些特性能够内定这一列使用什么的Binding去关联数据——那与ListBox有点分歧,ListBox使用的是DisplayMemberPath属性(类型是string)。假若想用更扑朔迷离的构造来表示这一题目或数量,则可为GridViewColumn设置HeadTemplate和CellTemplate,它们的连串都以DataTemplate。

运作效果如下:

图片 25

后台代码如下:

 

[csharp] view
plain
copyprint?

 

  1. public Window9()  
  2.        {  
  3.            InitializeComponent();  
  4.            DataTable dtInfo = CreateDataTable();  
  5.            for (int i = 0; i < 10; i++)  
  6.            {  
  7.                DataRow dr = dtInfo.NewRow();  
  8.                dr[0] = i;  
  9.                dr[1] = “猴王” + i;  
  10.                dr[2] = i + 10;  
  11.                dr[3] = “男”;  
  12.                dtInfo.Rows.Add(dr);  
  13.            }  
  14.    
  15.            this.listView1.ItemsSource = dtInfo.DefaultView;  
  16.        }  
  17.   
  18.   
  19.        private DataTable CreateDataTable()  
  20.        {  
  21.            DataTable dt = new DataTable(“newtable”);  
  22.              
  23.            DataColumn[] columns = new DataColumn[]{new DataColumn(“Id”),new DataColumn(“Name”),new DataColumn(“Age”),new DataColumn(“Sex”)};  
  24.            dt.Columns.AddRange(columns);  
  25.            return dt;  
  26.        }  

因此地方的例证大家已经精晓DataTable的DefaultView能够做为ItemSource来使用,拿DataTable直接用可以呢,让我们尝试看:

 

 

[csharp] view
plain
copyprint?

 

  1. InitializeComponent();  
  2.            DataTable dtInfo = CreateDataTable();  
  3.            for (int i = 0; i < 10; i++)  
  4.            {  
  5.                DataRow dr = dtInfo.NewRow();  
  6.                dr[0] = i;  
  7.                dr[1] = “猴王” + i;  
  8.                dr[2] = i + 10;  
  9.                dr[3] = “男”;  
  10.                dtInfo.Rows.Add(dr);  
  11.            }  
  12.    
  13.            this.listView1.ItemsSource = dtInfo;  

编写翻译的时候系统会报错提示:

 

谬误 1不能将品种“System.Data.DataTable”隐式转换为“System.Collections.IEnumerable”。存在二个显式转换(是不是缺少强制转换?)d:\自身的文书档案\visual
studio
2010\Projects\WpfApplication2\WpfApplication1\Window9.xaml.cs3642WpfApplication1

综上可得DataTable不能够直接拿来为ItemSource赋值。可是,当你把DataTable对象放在二个指标的Context属性的时候,并把一个ItemSource与二个既没有点名Source又尚未点名Path的Binding绑定起来的时候,Binding却能自行找到它的DefaultView并当作本人的Source来使用:

 

[csharp] view
plain
copyprint?

 

  1. DataTable dtInfo = CreateDataTable();  
  2.             for (int i = 0; i < 10; i++)  
  3.             {  
  4.                 DataRow dr = dtInfo.NewRow();  
  5.                 dr[0] = i;  
  6.                 dr[1] = “猴王” + i;  
  7.                 dr[2] = i + 10;  
  8.                 dr[3] = “男”;  
  9.                 dtInfo.Rows.Add(dr);  
  10.             }  
  11.   
  12.             this.listView1.DataContext = dtInfo;  
  13.             this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  

就此,要是你在代码中发觉把DataTable而不是DefaultView作为DataContext值,并且为ItemSource设置八个既无Path又从不Source的Binding的时候,千万别感觉到可疑。

 

1.3.9        使用XML数据作为Binding的源

到现在,.NETFramWork提供了两套处理XML数据的类库:

符合DOM(Document Object
Modle,文档对象模型)标准类库:包含XmlDocument、XmlElement、XmlNode、XmlAttribute等类。那套类库的性状是中规中矩,作用强大,但也背负了太多了XML的思想意识和复杂。

以LINQ(Language-Intergrated
Query,语言集成查询)为根基的类库:包涵XDocument,XElement,XNode,XAttribute等类。这套类库的特征是能够透过LINQ实行询问和操作,方便快捷。

上边大家注重视教育授一下标准项目标类库,基于LINQ的询问大家身处下一节切磋。

现行反革命先后设计只要提到到长途传输就离不开XML,因为多数数量传输是根据SOAP(Simple
Object Access
Protocol,不难对象访问协议)相关文书档案协议,而SOAP又是将对象系列化为XML文本进行传输。XML文本是树形结构的,所以XML能够方便的用于表示线性集合(如Array、List等)和树形结构数据。

注意:

在接纳XML数据作为Binding的Source的时候大家将应用XPath属性而不是Path属性来内定数量的来源。

咱俩先看1个线性集合的例证。上边包车型大巴XML文本是一组文本音信,大家要把它显得在三个ListView控件里:

 

[html] view
plain
copyprint?

 

  1. <?xml version=”1.0″ encoding=”utf-8″ ?>  
  2. <StudentList>  
  3.   <Student id=”1″>  
  4.     <Name>Andy</Name>  
  5.   </Student>  
  6.   <Student id=”2″>  
  7.     <Name>Jacky</Name>  
  8.   </Student>  
  9.   <Student id=”3″>  
  10.     <Name>Darren</Name>  
  11.   </Student>  
  12.   <Student id=”4″>  
  13.     <Name>DK</Name>  
  14.   </Student>  
  15.   <Student id=”1″>  
  16.     <Name>Jim</Name>  
  17.   </Student>  
  18. </StudentList>  

对应的XAML如下:

 

 

[csharp] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window10″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window10″ Height=”397″ Width=”485″>  
  5.     <StackPanel Width=”409″ Height=”331″ Background=”LightBlue”>  
  6.         <ListView Height=”302″ Name=”listView1″ Width=”396″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                     <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding XPath=@id}” Width=”80″>  
  10.                           
  11.                     </GridViewColumn>  
  12.                     <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding XPath=Name}” Width=”150″>  
  13.   
  14.                     </GridViewColumn>  
  15.                 </GridView>  
  16.             </ListView.View>  
  17.         </ListView>  
  18.     </StackPanel>  
  19. </Window>  

C#代码如下:

 

 

[csharp] view
plain
copyprint?

 

  1. private void BindingInfo()  
  2. {  
  3.     XmlDocument doc = new XmlDocument();  
  4.     doc.Load(@”d:\本人的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  5.   
  6.     XmlDataProvider dp = new XmlDataProvider();  
  7.     dp.Document = doc;  
  8.   
  9.     dp.XPath = @”StudentList/Student”;  
  10.     this.listView1.DataContext = dp;  
  11.     this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  
  12. }  

程序运转作效果果如下:

 

**图片 26

**

XMLDataProvider还有四个名为Source的属性,可以一直用它钦定XML文书档案所在地点(无论是XML文书档案是储存在该地硬盘依然网络地点),所以,后台代码也能够写成如下:

 

[csharp] view
plain
copyprint?

 

  1. private void BindingInfo()  
  2.         {  
  3.             //XmlDocument doc = new XmlDocument();  
  4.             //doc.Load(@”d:\小编的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  5.   
  6.             XmlDataProvider dp = new XmlDataProvider();  
  7.             dp.Source = new Uri(@”d:\自家的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  8.            // dp.Document = doc;  
  9.   
  10.             dp.XPath = @”StudentList/Student”;  
  11.             this.listView1.DataContext = dp;  
  12.             this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  
  13.         }  

XAML最重点的两句:DisplayMemberBinding=”{Binding
XPath=@id}”和DisplayMemberBinding=”{Binding
XPath=Name}”,他们分别为GridView两列钦赐了要珍视的XML路径—-很引人侧目,使用@符号加字符串表示的是XML成分的Attribute,不加@符号表示的是子级成分。

 

XML语言能够便宜的象征树形数据结构,上边包车型大巴例证是使用TreeView控件来体现全部多少层目录的文件系统,而且,本次把XML数据和XMLDataProvider对象直接写在XAML里面,代码中用到了HierarchicalDataTemplate类,那一个类具有ItemsSource属性,可知由那种Template展现的多少是能够有子级集合的。代码如下:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window11″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window11″ Height=”349″ Width=”545″>  
  5.     <Window.Resources>  
  6.         <XmlDataProvider x:Key=”xdp” XPath=”FileSystem/Folder”>  
  7.             <x:XData>  
  8.                 <FileSystem xmlns=””>  
  9.                     <Folder Name=”Books”>  
  10.                         <Folder Name=”Programming”>  
  11.                             <Folder Name=”Windows”>  
  12.                                 <Folder Name=”WPF”>  
  13.                                    
  14.                                 </Folder>  
  15.                                 <Folder Name=”Winform”>  
  16.   
  17.                                 </Folder>  
  18.                                 <Folder Name=”ASP.NET”>  
  19.   
  20.                                 </Folder>  
  21.                             </Folder>  
  22.                         </Folder>  
  23.                     </Folder>  
  24.                     <Folder Name=”Tools”>  
  25.                         <Folder Name=”Development”/>  
  26.                         <Folder Name=”Designment”/>  
  27.                         <Folder Name=”Players”/>  
  28.                     </Folder>  
  29.                 </FileSystem>  
  30.             </x:XData>  
  31.         </XmlDataProvider>  
  32.     </Window.Resources>  
  33.     <Grid>  
  34.         <TreeView Height=”283″ HorizontalAlignment=”Left”  Name=”treeView1″ VerticalAlignment=”Top” Width=”511″ ItemsSource=”{Binding Source={StaticResource ResourceKey=xdp}}”>  
  35.             <TreeView.ItemTemplate>  
  36.                 <HierarchicalDataTemplate ItemsSource=”{Binding XPath=Folder}”>  
  37.                     <TextBlock Height=”23″ HorizontalAlignment=”Left”  Name=”textBlock1″ Text=”{Binding XPath=@Name}” VerticalAlignment=”Top” />  
  38.                 </HierarchicalDataTemplate>  
  39.             </TreeView.ItemTemplate>  
  40.         </TreeView>  
  41.           
  42.     </Grid>  
  43. </Window>  

注意:

 

将XmlDataProvider直接写在XAML代码里面,那么他的数码供给放在<x:XData>标签中。

由于本例子设计到了StaticResource和HierarchicalDataTemplate,都以末端的始末,相对相比较难懂,等求学完前面包车型地铁Resource和Template章节过后再回去便会精通于胸。

程序运转效果如下图:

图片 27

1.3.10      使用LINQ检索结果做为Binding 的源

至3.0本子开首,.NET Framework开始帮忙LINQ(Language-Intergrated Query
 
语言集成查询),使用LINQ,大家得以一本万利的操作集合对象、DataTable对象和XML对象不必动辄不动把有个别层foreach循环嵌套在同步却只是为了完结1个非常粗略的职责。

LINQ查询的结果是贰个IEnumerable<T>类型对象,而IEnumerable<T>又派生自IEnumerable,所以它能够作为列表控件的ItemsSource来使用。

先创设3个名为Student的类:

 

[csharp] view
plain
copyprint?

 

  1. public class Student  
  2.   {  
  3.       public int Id { get; set; }  
  4.       public string Name { get; set; }  
  5.       public int Age { get; set; }  
  6.   }  

XAML代码如下:

 

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window12″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window12″ Height=”372″ Width=”538″>  
  5.     <Grid>  
  6.         <ListView Height=”311″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”listView1″ VerticalAlignment=”Top” Width=”494″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                     <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding Id}” Width=”100″/>  
  10.                     <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding Name}” Width=”100″/>  
  11.                     <GridViewColumn Header=”Age” DisplayMemberBinding=”{Binding Age}” Width=”100″/>  
  12.                 </GridView>  
  13.             </ListView.View>  
  14.         </ListView>  
  15.     </Grid>  
  16. </Window>  

 

 

后台代码如下:

[csharp] view
plain
copyprint?

 

  1. private void BindingData()  
  2.         {  
  3.             List<Student> infos = new List<Student>()  
  4.             {  
  5.                 new Student(){Id=1, Age=29, Name=”Tim”},  
  6.                  new Student(){Id=1, Age=28, Name=”Tom”},  
  7.                   new Student(){Id=1, Age=27, Name=”Kyle”},  
  8.                    new Student(){Id=1, Age=26, Name=”Tony”},  
  9.                     new Student(){Id=1, Age=25, Name=”Vina”},  
  10.                      new Student(){Id=1, Age=24, Name=”Mike”}  
  11.             };  
  12.             this.listView1.ItemsSource = from stu in infos where stu.Name.StartsWith(“T”) select stu;  
  13.         }  

尽管数额存放在一个DataTable对象里面,则后台代码如下:

 

[csharp] view
plain
copyprint?

 

  1. private void BindingDataByDataTable()  
  2.        {  
  3.            DataTable dtInfo = CreateDataTable();  
  4.            this.listView1.ItemsSource = from row in dtInfo.Rows.Cast<DataRow>()  
  5.                                         where Convert.ToString(row[“Name”]).StartsWith(“T”)  
  6.                                         select new Student()  
  7.                                         {  
  8.                                             Id = Convert.ToInt32(row[“Id”]), Name=Convert.ToString(row[“Name”]),Age=Convert.ToInt32(row[“Age”])  
  9.                                         };  
  10.              
  11.        }  

万一数额存款和储蓄在XML里面,存储格式如下:

 

 

[html] view
plain
copyprint?

 

  1. <?xml version=”1.0″ encoding=”utf-8″ ?>  
  2. <StudentList>  
  3.   <Class>  
  4.     <Student Id=”0″ Age=”29″ Name=”Tim” />  
  5.     <Student Id=”0″ Age=”28″ Name=”Tom” />  
  6.     <Student Id=”0″ Age=”27″ Name=”Mess” />  
  7.   </Class>  
  8.   <Class>  
  9.     <Student Id=”0″ Age=”26″ Name=”Tony” />  
  10.     <Student Id=”0″ Age=”25″ Name=”Vina” />  
  11.     <Student Id=”0″ Age=”24″ Name=”Emily” />  
  12.   </Class>  
  13. </StudentList>  

则代码是这么(注意:xd.Descendants(“Student”)那一个办法,它能够跨XML的层级):

 

 

[csharp] view
plain
copyprint?

 

  1. private void BindingDataByXml()  
  2.         {  
  3.             XDocument xd = XDocument.Load(@”d:\自个儿的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\testDate.xml”);  
  4.   
  5.             this.listView1.ItemsSource = from element in xd.Descendants(“Student”)  
  6.                                          where element.Attribute(“Name”).Value.StartsWith(“T”)  
  7.                                          select new Student()  
  8.                                              {  
  9.                                                  Name = element.Attribute(“Name”).Value,  
  10.                                                  Id = Convert.ToInt32(element.Attribute(“Id”).Value),  
  11.                                                  Age = Convert.ToInt32(element.Attribute(“Age”).Value)  
  12.                                              };  
  13.         }  

 

 

程序运营效果如下图:

**图片 28

**

1.3.11    使用ObjectDataProvider作为binding的Source

优质图景下,上游程序员将类设计好、使用性质把多少暴表露来,下游程序员将那么些类作为Binding的Source、把性能作为Binding的Path来成本这几个类。但很难保障一个类的属性都用属性暴揭穿来,比如我们要求的多少也许是方法的重临值。而再度规划底层类的危害和花费会相比较高,况且黑盒引用类库的图景下大家不或然改变已经编写翻译好的类,那时候要求使用ObjectDataProvider来包装做为Binding源的数目对象了。

ObjcetDataProvider
顾名思义正是把对指标作为数据源提须要Binding。前边还论及过XmlDataProvider,那五个类的父类都以DataSourceProvider抽象类。

现行反革命有叁个名为Calculator的类,它具有加、减、乘、除的主意:

 

[csharp] view
plain
copyprint?

 

  1. public class Caculate  
  2. {  
  3.     public string Add(string arg1,string arg2)  
  4.     {  
  5.         double x = 0;  
  6.         double y = 0;  
  7.         double z = 0;  
  8.         if(double.TryParse(arg1,out x)&&double.TryParse(arg2,out y))  
  9.         {  
  10.             z = x + y;  
  11.             return z.ToString();  
  12.         }  
  13.         return “Iput Error”;  
  14.     }  
  15.   
  16.     //别的方法简便  
  17. }  

大家先写多少个非凡简单的小例子来打听下ObjectDataProvider类。随便新建3个WPF窗体,窗体内拖放多少个控件,控件的Click事件如下:

 

 

[csharp] view
plain
copyprint?

 

  1. private void button1_Click(object sender, RoutedEventArgs e)  
  2.      {  
  3.          ObjectDataProvider odp = new ObjectDataProvider();  
  4.          odp.ObjectInstance = new Caculate();  
  5.          odp.MethodName=”Add”;  
  6.          odp.MethodParameters.Add(“100”);  
  7.          odp.MethodParameters.Add(“200”);  
  8.          MessageBox.Show(odp.Data.ToString());  
  9.   
  10.      }  

运作程序,单击button我们汇合到如下界面:

 

图片 29

通过这些程序我们能够掌握到ObjectDataProvider对象和它被打包的指标关系如下图:

图片 30

 

打听了ObjectDataProvider的应用格局,大家看看哪些把它当作Binding的Source来使用。程序的XAML代码和截图如下:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window14″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window14″ Height=”202″ Width=”345″>  
  5.     <StackPanel Background=”LightBlue”>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  7.         <TextBox Height=”23″ Name=”textBox2″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  8.         <TextBox Height=”23″ Name=”textBox3″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  9.     </StackPanel>  
  10. </Window>  

图片 31

 

以此程序完毕的法力是,笔者在前四个TextBox里面输入值的时候,第四个TextBox会显示前七个文本框里面相加之和。把代码写在贰个名为SetBinding的艺术里面,然后在窗体的构造器里面调用这几个办法:

 

[csharp] view
plain
copyprint?

 

  1. private void SetBinding()  
  2.        {  
  3.            ObjectDataProvider objpro = new ObjectDataProvider();  
  4.            objpro.ObjectInstance = new Caculate();  
  5.            objpro.MethodName = “Add”;  
  6.            objpro.MethodParameters.Add(“0”);  
  7.            objpro.MethodParameters.Add(“0”);  
  8.            Binding bindingToArg1 = new Binding(“MethodParameters[0]”) { Source=objpro,BindsDirectlyToSource=true, UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged};  
  9.            Binding bindingToArg2 = new Binding(“MethodParameters[1]”) { Source=objpro,BindsDirectlyToSource=true,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};  
  10.            Binding bindToResult = new Binding(“.”) { Source=objpro};  
  11.            this.textBox1.SetBinding(TextBox.TextProperty, bindingToArg1);  
  12.            this.textBox2.SetBinding(TextBox.TextProperty, bindingToArg2);  
  13.            this.textBox3.SetBinding(TextBox.TextProperty,bindToResult);  
  14.        }  

让我们先来分析一下方面两段代码,前边说过,ObjectDataProvider类的效应是包装3个以艺术暴光数据的对象,那里大家先创建了贰个ObjectDataProvider的目的,然后用三个Caculate对象为其ObjectInstance对象赋值—那就把二个Caculate对象包装在了ObjectDataProvider里面。还有别的3个措施来创设被包裹的目的,那正是告诉包装对象被打包对象的项目和期望调用的构造器,让ObjectDataProvider自个儿来制造对象,代码差不多是如此:

 

 

[csharp] view
plain
copyprint?

 

  1. //—  
  2.            objpro.ObjectInstance = typeof(Caculate);  
  3.            objpro.ConstructorParameters.Add(arg1);  
  4.            objpro.ConstructorParameters.Add(arg2);  
  5.            //—-  

因为在XAML中创制对象相比费心,可读性差,所以大家一般会在XAML代码中使用那种钦赐项目和构造器的情势。

 

继之,大家应用MethodName属性钦赐要调用的Caculator对象中名为Add的章程—难题又来了,要是Caculator有多少个构造器参数的措施Add应该如何区分?大家掌握,重载方法的分别在于参数列表,紧接着两句正是向MethodParameter属性里面插手七个string类型的参数,那就也等于告诉ObjectDataProvider对象去调用Caculator对象中具有四个string类型参数的Add方法,换句话说,MethodParameter对于参数的反响是非凡敏锐的。

准备好数据源之后,大家准备开创Binding。后面大家曾经讲过使用索引器作为Binding的Path,第三个Binding它的Source是六个ObjectDataProvider对象,Path是ObjectDataProvider中MethodParameters所引述的首先个因素。BindsDirectlyToSource那句话是告诉Binding只是将UI上的值传递给源而不是被ObjectDataProvider包装的Caculator,同时UpdateSourceTrigger设置为UI只要一有变化就更新Source。第一个Binding只是对第三个的翻版,只是把Path属性指向了第三个元素。第多个binding依旧采用ObjectDataProvider作为Source,但利用“.”作为帕特h—-后面讲过,当数据源本人正是数额的时候就用“.”来做为Path,在XAML中”.”能够不写。

注意:

在ObjectDataProvider对象作为Binding的Source的时候,那么些目的自笔者就代表了数量,所以那边的Path使用的“.”,而不是Data属性。

最终几行正是将Binding对象关系到三个TextBox对象上。程序运转效果如下:

图片 32

貌似景观下数据从那边来,哪儿正是Binding的Source,数据到哪个地方去,哪儿正是Binding
的Target。按这么些理论,前七个TextBox应该是ObjcetDataProvider的源,而ObjcetDataProvider对象又是最后二个TextBox的源。但实则,四个TextBox都是ObjcetDataProvider作为数据源,只是前三个在数码流向上做了限定,那样做的原故不外乎有四个:

① 、ObjcetDataProvider的MethodParameter不是信赖属性,无法当做Binding的目的。

贰 、数据驱动UI理念须要大家尽量的接纳数据对象作为Binding的Source而把UI当做Binding的Target。

1.3.12    使用Binding的RelativeSource

当八个Binding有肯定的来源的时候,咱们能够透过Source大概ElementName赋值的措施让Binding与之提到。有些时候大家无法显著作为Source对象叫什么名字,可是大家知晓它与做为Binding目的对象在UI上的相对关系,比如控件自个儿涉嫌自身的某部数据,关联本人某级容器的数量,这时候就须要用到Binding的RelativeSource属性。

RelativeSource属性的品种是RelativeSource类,通过那么些类的多少个静态只怕非静态的品质大家能够操纵它寻找绝对数据源的艺术。请看上面那段代码:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window15″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window15″ Height=”375″ Width=”516″>  
  5.     <Grid Background=”Red” Margin=”10″ x:Name=”gd1″>  
  6.         <DockPanel x:Name=”dp1″ Margin=”10″ Background=”Orange”>  
  7.             <Grid Background=”Yellow” Margin=”10″ x:Name=”gd2″>  
  8.                 <DockPanel Name=”dp2″ Margin=”10″ Background=”LawnGreen”>  
  9.                     <TextBox  Name=”textBox1″  Margin=”10″ FontSize=”24″/>  
  10.                 </DockPanel>  
  11.             </Grid>  
  12.         </DockPanel>  
  13.     </Grid>  
  14. </Window>  

界面运维结果如下:

 

图片 33

大家把TextBox的Text属性关联到外围容器的Name属性上。在窗体的构造器里面添加如下几行代码:

 

[csharp] view
plain
copyprint?

 

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);  
  2.            rs.AncestorLevel = 1;  
  3.            rs.AncestorType = typeof(Grid);  
  4.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  5.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

或在XAML代码中插入等效代码:

 

 

[html] view
plain
copyprint?

 

  1. <TextBox  Name=”textBox1″  Margin=”10″ FontSize=”24″ Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Grid},AncestorLevel=1}}”/>  

AncestorLevel属性钦定的是以Binding目的控件为起源的层级偏移量—gd2的偏移量是1,gd2的偏移量是2,依次类推。AncestorType属性告诉Binding去找什么样品种的靶子作为协调的源,不是那个类别的对象会被跳过。下面那段代码的意味是告诉Binding从自身的第3层依次向外找,找到第③个Grid类型对象后把它当做本身的源。运维作效果果如下图:

 

图片 34
设若把代码改成如下那样:

 

[csharp] view
plain
copyprint?

 

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);  
  2.            rs.AncestorLevel = 2;  
  3.            rs.AncestorType = typeof(DockPanel);  
  4.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  5.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

照旧把XAML代码改成如下:

 

 

[html] view
plain
copyprint?

 

  1. Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DockPanel},AncestorLevel=2}}”  

运作效果如下:

 

图片 35

若是Text博克斯要求关联本身的Name属性,那么代码应该如此写:

 

[csharp] view
plain
copyprint?

 

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.Self);  
  2.             
  3.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  4.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

对应的XAML代码如下:

 

 

[html] view
plain
copyprint?

 

  1. Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=Self}}”  

运行效果如下图:

 

图片 36

RelativeSource类的Mode属性是RelativeSourceMode枚举,它的值有:PriviousData、TemplatedParent、Self和FindAncestor。RelativeSource还有一个静态属性:PriviousData、Self、TemplatedParent,它们的花色是RelativeSource类。实际上那一个静态属性便是创立2个RelativeSource的实例、把实例的Mode设置为相呼应的值,然后回来那么些实例。之所以准备那二个静态属性是为着在XAML代码里面一贯获取RelativeSource实例。

在DataTemplate中时常用到那那3个静态属性,学习DataTemplate的时候请留心它们的施用方式。

1.4      binding对数码的转移和校验

前边我们早就知道Binding的效益便是架在Source和Target之间的大桥,数据足以在那座大桥的帮扶下去流通。就如现实社会中桥梁须要设置安全检查和关卡一样,Binding那座桥上也足以安装关卡对数码实行验证,不仅如此,若是Binding两端需求区别的数据类型的时候我们还是能为多少设置转换器。

Binding用于数据有效性校验的卡子是他的ValidationRules属性,用于数据类型转换的关卡是它的Convert属性。

1.4.1          Binding的多寡校验

Binding的ValidationRules属性是Collection<ValidationRule>,从它的名目和数据类型大家得以摸清能够为每一个Binding设置多少个数据校验条件,每一个规范是二个ValidationRule对象。ValidationRule是3个抽象类,在选拔的时候我们要求创设它的派生类并贯彻它的Validate方法的重返值是ValidateionResult类型对象,假诺由此验证,就把ValidateionResult对象的IsValidate属性设为true,反之,则须求将IsValidate设置为false并为其ErrorContent属性设置二个老少咸宜的新闻内容(一般是字符串)。

下边那一个顺序的UI绘制2个Text博克斯和3个Slider,然后在后台C#代码中国建工业总会公司立Binding把它们关联起来—-
已Slide为源,TextBox为目的。Slider的取值范围是0~100,也正是说我们需求验证TextBox中输入的值是否在0~100之间。

先后的XAML部分如下:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window16″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window16″ Height=”300″ Width=”300″>  
  5.     <StackPanel Background=”AliceBlue” Margin=”10″>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Width=”200″ Margin=”20″/>  
  7.         <Slider Height=”23″ Name=”slider1″ Width=”219″ Maximum=”100″ />  
  8.     </StackPanel>  
  9. </Window>  

为了拓展校验,大家准备多个ValidationRule的派生类,内容如下:

 

 

[csharp] view
plain
copyprint?

 

  1. public class RangeValidationRule : ValidationRule  
  2. {  
  3.   
  4.     public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)  
  5.     {  
  6.         double d = 0;  
  7.         if(double.TryParse(value.ToString(),out d))  
  8.         {  
  9.             if(d>=0&&d<=100)  
  10.             {  
  11.                 return new ValidationResult(true,null);  
  12.             }  
  13.         }  
  14.         return new ValidationResult(false,”ErrorContent”);  
  15.     }  
  16. }  

接下来在窗体里面建立Binding:

 

 

[csharp] view
plain
copyprint?

 

  1. public Window16()  
  2.        {  
  3.            InitializeComponent();  
  4.            Binding bind =new Binding(“Value”) { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};  
  5.            ValidationRule rule = new RangeValidationRule();  
  6.            rule.ValidatesOnTargetUpdated = true;  
  7.            bind.ValidationRules.Add(rule);  
  8.   
  9.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  10.        }  

姣好后运转程序,当输入0~100之间的值的时候程序平常化展现,可是输入区间之外的值的时候TextBox会显示为革命边框,表示值是不对的,不能够传值给Source。效果如下图:

 

图片 37图片 38

先把Silider的取值范围从0~100改为-100~200:

图片 39图片 40

您大概回看,在验证错误的时候,ValidationResult会指引一条错误新闻,那么怎么着利用这条错误消息呢?想要用到那或多或少,需求动用前边会详细讲解到的文化—–路由事件(Routed
伊夫nt)。

第二在创制Binding
的时候要把Binding的指标的NotifyOnValidationError属性设置为true,那样,当数码校验失败的时候Binding就好像报告警方器一样产生2个信号。那一个信号会在已Binding对象的Target为起源的UI树上举行传播。信号没到达二个节点,借使那么些节点设置了对那种信号的侦听器(事件处理器),那么那个侦听器就会被触发并拍卖那么些信号,信号处理完结后,还足以是或不是让信号继续本着UI树向上传播—那正是路由事件。信号在UI树上传递的长河称为路由(Route)。

确立Binding的代码如下:

 

[csharp] view
plain
copyprint?

 

  1. public Window16()  
  2.        {  
  3.            InitializeComponent();  
  4.            Binding bind =new Binding(“Value”) { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};  
  5.            ValidationRule rule = new RangeValidationRule();  
  6.            rule.ValidatesOnTargetUpdated = true;  
  7.            bind.ValidationRules.Add(rule);  
  8.            bind.NotifyOnValidationError = true;  
  9.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  10.            this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));  
  11.        }  

用于侦听校验错误事件的事件处理器如下:

 

 

[csharp] view
plain
copyprint?

 

  1. private void ValidationError(object sender, RoutedEventArgs e)  
  2.         {  
  3.             if (Validation.GetErrors(textBox1).Count > 0)  
  4.             {  
  5.                 this.textBox1.ToolTip = Validation.GetErrors(textBox1)[0].ErrorContent.ToString();  
  6.             }  
  7.             else  
  8.             {  
  9.                 this.textBox1.ToolTip = “”;  
  10.             }  
  11.         }  

次第③旦校验退步,就会动用ToolTip提示用户,如下图:

 

图片 41

1.4.2    Binding的数码转换

前面的成都百货上千例子大家都在采纳Binding将TextBox和Slider之间建立关联—-Slider控件作为Source(帕特h的Value属性),TextBox作为Target(目的属性为Text)。不知底大家有没有在意到,Slider的Value属性是Double类型值,而TextBox的Text属性是string类型的值,在C#那种强类型语言中却能够来回自如,是怎么回事呢?

原来Binding还有其余一种机制称为数据转换,当Source端内定的Path属性值和Target端钦命的靶子属性不均等的时候,我们得以拉长数据转换器(DataConvert)。上边我们关系的标题实际上正是double和stirng类型互相转换的标题,因为拍卖起来比较不难,所以WPF类库就和好帮我们做了,但稍事数据类型转换就不是WPF能帮大家做的了,例如下边包车型大巴那种情景:

 

  • Source里面包车型客车值是Y、N、X四个值(可能是Char类型,string类型或许自定义枚举类型),UI上相应的是CheckBox控件,须要把那三个值映射为它的IsChecked属性值(bool类型)。
  • 当TextBox里面必须输入的有类容时候用于登录的Button才会合世,那是string类型与Visibility枚举类型或bool类型之间的转换(Binding的Model将是oneway)。
  • Source里面包车型大巴值有恐怕是Male或FeMale(string或枚举),UI是用以体现图片的Image控件,那时候须要把Source里面值转换为对应的头像图片U昂CoraI(亦是oneway)。

 

当境遇那些情况,大家不得不本人动手写Converter,方法是创立三个类并让这一个类完毕IValueConverter接口,IValueConverter定义如下:

 

[csharp] view
plain
copyprint?

 

  1. public interface IValueConverter  
  2. {  
  3.     object Convert(object value, Type targetType, object parameters, CultureInfo culture);  
  4.     object ConvertBack(object value, Type targetType, object parameters, CultureInfo culture);  
  5. }  

当数码从Binding的Source流向Target的时候,Convert方法将被调用;反之ConvertBack将被调用。那四个格局的参数列表一模一样:第二个参数为Object。最大限度的保险了Convert的重大。第一个参数用于鲜明再次回到参数的回来类型。第多少个参数为了将附加的参数字传送入方法,若必要传递四个消息,则必要将消息做为二个汇聚传入即可。

 

Binding对象的Mode属性将震慑那五个法子的调用;假如Mode为TwoWay或Default行为与TwoWay一致则四个点子都有也许被调用。借使Mode是OneWay大概Default行为与OneWay一致则唯有Convert方法会被调用。别的情形同理。

上面这几个事例是四个Converter的总结实例,程序的用途是向玩家呈现一些军用飞机的事态新闻。

首先创制多少个自定义数据类型:

 

[csharp] view
plain
copyprint?

 

  1. public enum Category  
  2.    {  
  3.        Bomber,  
  4.        Fighter  
  5.    }  
  6.   
  7.    public enum State  
  8.    {  
  9.        Available,  
  10.        Locked,  
  11.        Unknown  
  12.    }  
  13.   
  14.    public class Plane  
  15.    {  
  16.        public Category category { get; set; }  
  17.        public State state { get; set; }  
  18.        public string name { get; set; }  
  19.    }  

在UI里,Category的场所被映射为图标,那多个图标已经被本人放入项目中,如图:

 

图片 42

再就是飞机的State属性在UI里面被映射为CheckBox。因为存在以上两种炫耀关系。大家供给提供几个Converter:二个有Categroy类型单向转换为string类型(XAML会把string解析为图片财富),另一个是State和bool类型直接的双向转换。代码如下:

 

[csharp] view
plain
copyprint?

 

  1. public class CategoryToSourceConverter:IValueConverter  
  2.     {  
  3.   
  4.         public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  5.         {  
  6.             Category category = (Category)value;  
  7.             switch (category)  
  8.             {  
  9.                 case Category.Bomber:  
  10.                     return @”ICONS/Bomber.png”;  
  11.                      
  12.                 case Category.Fighter:  
  13.                     return @”ICONS/Fighter.png”;  
  14.                      
  15.                 default:  
  16.                     return null;  
  17.                       
  18.             }  
  19.         }  
  20.   
  21.         public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  22.         {  
  23.             throw new NotImplementedException();  
  24.         }  
  25.     }  

 

[csharp] view
plain
copyprint?

 

  1. public class StateToNullableBoolConverter:IValueConverter  
  2.     {  
  3.   
  4.         public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  5.         {  
  6.             State state = (State)value;  
  7.             switch (state)  
  8.             {  
  9.                 case State.Available:  
  10.                     return true;  
  11.                       
  12.                 case State.Locked:  
  13.                     return false;  
  14.                 case State.Unknown:  
  15.                       
  16.                 default:  
  17.                     return null;  
  18.             }  
  19.         }  
  20.   
  21.         public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  22.         {  
  23.             bool? nb = (bool?)value;  
  24.             switch (nb)  
  25.             {  
  26.                 case true:  
  27.                     return State.Available;  
  28.                 case false:  
  29.                     return State.Locked;  
  30.                 case null:  
  31.                 default:  
  32.                     return State.Unknown;  
  33.                       
  34.             }  
  35.         }  
  36.     }  

下边我们来看望哪些在XAML代码里面来消费那么些Converter:

 

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window17″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:local=”clr-namespace:WpfApplication1.BLL”  
  5.         Title=”Window17″ Height=”327″ Width=”460″>  
  6.     <Window.Resources>  
  7.         <local:CategoryToSourceConverter x:Key=”cts” />  
  8.         <local:StateToNullableBoolConverter x:Key=”snb” />  
  9.     </Window.Resources>  
  10.     <StackPanel Name=”stackPanel1″ Background=”AliceBlue” Margin=”10″>  
  11.         <ListBox  Name=”listBox1″ Height=”160″ Margin=”5″>  
  12.             <ListBox.ItemTemplate>  
  13.                 <DataTemplate>  
  14.                     <StackPanel Orientation=”Horizontal”>  
  15.                         <Image Height=”16″ Name=”image1″ Stretch=”Fill” Width=”16″ Source=”{Binding Path=category,Converter={StaticResource cts}}”/>  
  16.                         <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding name}” Margin=”8,0″ Width=”80″/>  
  17.                         <CheckBox  Height=”16″ Name=”checkBox1″ IsChecked=”{Binding Path=state,Converter={StaticResource snb}}” IsThreeState=”True”/>  
  18.                     </StackPanel>  
  19.                 </DataTemplate>  
  20.             </ListBox.ItemTemplate>  
  21.         </ListBox>  
  22.         <Button Content=”Load” Height=”23″ Name=”button1″ Width=”131″ Margin=”5″ Click=”button1_Click” />  
  23.         <Button Content=”Save” Height=”23″ Name=”button2″ Width=”131″ Margin=”5″ Click=”button2_Click” />  
  24.     </StackPanel>  
  25. </Window>  

Load按钮的事件处理器负责把一组飞机的数据赋值给ListBox的ItemSource属性,Save的Click事件承担把用户修改过的数目写入文件:

 

 

[csharp] view
plain
copyprint?

 

  1. /// <summary>  
  2.         /// Load按钮事件处理器  
  3.         /// </summary>  
  4.         /// <param name=”sender”></param>  
  5.         /// <param name=”e”></param>  
  6.         private void button1_Click(object sender, RoutedEventArgs e)  
  7.         {  
  8.             List<Plane> infos = new List<Plane>() {   
  9.             new Plane(){ category= Category.Bomber,name=”B-1″, state= State.Unknown},  
  10.             new Plane(){ category= Category.Bomber,name=”B-2″, state= State.Unknown},  
  11.             new Plane(){ category= Category.Fighter,name=”F-22″, state= State.Locked},  
  12.             new Plane(){ category= Category.Fighter,name=”Su-47″, state= State.Unknown},  
  13.             new Plane(){ category= Category.Bomber,name=”B-52″, state= State.Available},  
  14.             new Plane(){ category= Category.Fighter,name=”J-10″, state= State.Unknown},  
  15.             };  
  16.             this.listBox1.ItemsSource = infos;  
  17.         }  
  18.         /// <summary>  
  19.         /// Save按钮事件处理器  
  20.         /// </summary>  
  21.         /// <param name=”sender”></param>  
  22.         /// <param name=”e”></param>  
  23.         private void button2_Click(object sender, RoutedEventArgs e)  
  24.         {  
  25.             StringBuilder sb = new StringBuilder();  
  26.             foreach (Plane item in listBox1.Items)  
  27.             {  
  28.                 sb.AppendLine(string.Format(“Categroy={0},State={1},Name={2}”,item.category,item.state,item.name));  
  29.             }  
  30.             File.WriteAllText(@”D:\PlaneList.text”,sb.ToString());  
  31.         }  

运作程序,单击CheckBox修改飞机的State,如图:

 

图片 43图片 44

单击Save后打开D:\\PlaneList.text数据如下图:

图片 45

1.5   MultiBinding(多路Binding)

有时UI必要体现的数码来源不止三个数额出自决定,那一个时候就须要动用MultiBinding,即多路绑定。MultiBinding与Binding一样均以BindingBase为基类,也正是说,凡是能用Binding的场地都能动用MultiBinding。MutiBinding具有三个Bindings的质量,其项目是Connection<BindingBase>,通过这一个性格,MultiBinding把一组Binding对象聚合起来,处在这么些Binding结合中的对象足以享有自身的数码校验和转换机制。它们汇聚起来的数额将同台决定传往MultiBinding目的的多少。如下图:

图片 46

考虑那样一个需求,有一个用来新用户注册的UI(5个TextBox和一个Button),还有如下一些限制:

 

  • 首先,1个TextBox用于输入用户名,供给数据必须一律。
  • 其三,多少个TextBox用于显示输入的邮箱,须要数据必须一致。
  • 当TextBox的剧情总体符合供给的时候,Button可用。

 

此UI的XAML代码如下:

 

[html] view
plain
copyprint?

 

  1. <Window x:Class=”WpfApplication1.Window18″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window18″ Height=”300″ Width=”300″>  
  5.     <StackPanel Name=”stackPanel1″  Margin=”10″ Background=”AliceBlue”>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Margin=”5″ />  
  7.         <TextBox Height=”23″ Name=”textBox2″ Margin=”5″ />  
  8.         <TextBox Height=”23″ Name=”textBox3″ Margin=”5″ />  
  9.         <TextBox Height=”23″ Name=”textBox4″ Margin=”5″ />  
  10.         <Button Content=”Regist” Height=”23″ Name=”btnSubmit” Width=”75″  Margin=”10″/>  
  11.     </StackPanel>  
  12. </Window>  

后台代码如下:

 

 

[csharp] view
plain
copyprint?

 

  1. public Window18()  
  2.        {  
  3.            InitializeComponent();  
  4.            SetBinding();  
  5.        }  
  6.   
  7.        private void SetBinding()  
  8.        {  
  9.            //准备基础Binding  
  10.            Binding bind1 = new Binding(“Text”) { Source=textBox1};  
  11.            Binding bind2 = new Binding(“Text”) { Source = textBox2 };  
  12.            Binding bind3 = new Binding(“Text”) { Source = textBox3 };  
  13.            Binding bind4 = new Binding(“Text”) { Source = textBox4 };  
  14.   
  15.            //准备MultiBinding  
  16.            MultiBinding mb = new MultiBinding() { Mode= BindingMode.OneWay};  
  17.            mb.Bindings.Add(bind1);//注意,MultiBinding对子成分的一一是很乖巧的。  
  18.            mb.Bindings.Add(bind2);  
  19.            mb.Bindings.Add(bind3);  
  20.            mb.Bindings.Add(bind4);  
  21.            mb.Converter = new MultiBindingConverter();  
  22.            ///将Binding和MultyBinding关联  
  23.            this.btnSubmit.SetBinding(Button.IsVisibleProperty, mb);  
  24.        }  

注意:

 

 

  • MultiBinding对子成分的依次相当敏感,因为那个数目控制了汇总到Convert里多少的顺序。
  • MultiBinding的Converter达成的是IMultiValueConverter。

 

本例的Converter代码如下:

 

[csharp] view
plain
copyprint?

 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Windows.Data;  
  6.   
  7. namespace WpfApplication1.BLL  
  8. {  
  9.     public class MultiBindingConverter:IMultiValueConverter  
  10.     {  
  11.         public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
  12.         {  
  13.             if(!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))&&values[0].ToString()==values[1].ToString()&&values[3].ToString()==values[4].ToString())  
  14.             {  
  15.                 return true;  
  16.             }  
  17.             return false;  
  18.         }  
  19.         /// <summary>  
  20.         /// 该方法不会被调用  
  21.         /// </summary>  
  22.         /// <param name=”value”></param>  
  23.         /// <param name=”targetTypes”></param>  
  24.         /// <param name=”parameter”></param>  
  25.         /// <param name=”culture”></param>  
  26.         /// <returns></returns>  
  27.         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)  
  28.         {  
  29.             throw new NotImplementedException();  
  30.         }  
  31.     }  
  32. }  

程序运行效果如图:

 

图片 47 
  图片 48

小结:

WPF的大旨理念是变古板的UI驱动数据变成数据驱动UI,支撑这一个理念的基础便是本章讲的Data
Binding和与之毛将焉附荣辱与共的数量校验和数量转换。在应用Binding的时候,最要害的就是安装它的源和路径。

 

 

Data Binding到此讲解结束。

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window7″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:Str=”clr-namespace:System;assembly=mscorlib”  
  5.         Title=”Window7″ Height=”300″ Width=”300″>  
  6.     <Grid>  
  7.         <Grid.DataContext>  
  8.             <Str:String>Hello DataContext</Str:String>  
  9.         </Grid.DataContext>  
  10.         <StackPanel>  
  11.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock1″ Text=”{Binding}” VerticalAlignment=”Top” />  
  12.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock2″ Text=”{Binding}” VerticalAlignment=”Top” />  
  13.             <TextBlock Height=”23″ HorizontalAlignment=”Left” Margin=”15″ Name=”textBlock3″ Text=”{Binding}” VerticalAlignment=”Top” />  
  14.         </StackPanel>  
  15.           
  16.     </Grid>  
  17. </Window>  

运转效果如下图:

 

图片 49

你大概回看,Binding怎么会活动向UI成分上一层查找DataContext并把它作为协调的Source呢?其实,“Binding沿着UI成分树向上找”只是WPF给大家的二个错觉,Binding并不曾那么智能。之所以会那样是因为DataContext是2个“重视属性”,后边的章节我们会详细描述,重视属性有八个很分明的特点正是你没有为某些控件的重视属性赋值的时候,控件会把本身容器的属性值接过来当作自个儿的属性值。实际上属性值是本着UI成分树向下传递的。

在其实工作中,DataContext属性值的运用至极的灵活。比如:

当UI上的四个控件都选拔Binding关怀同三个指标变化的时候,不要紧接纳DataContext。

当作为Source的靶子不能够被一贯访问的时候—-比如B窗体内的控件想把A窗体里的控件当作自身的Binding源时,然而A窗体内的控件可访问级别是private类型,这是就能够把那个控件恐怕控件值作为窗体A的DataContext(那性格情是Public级其余)那样就足以揭发数据了。

形象的说,那时候外层的数量就一定于3个数额的“至高点”,只要把成分放上去,别人就可见看见。此外DataContext本人便是3个凭借属性,大家能够运用Binding把它涉及到二个数目源上。

1.3.7     使用集合对象作为列表控件的ItemsSource

有了DataContext作为基础,大家再来看看把集合类型对象作为Binding源的事态。

WPF中的列表式控件都派生自ItemControl类,自然也持续了ItemSource那特性格。ItemSource可以接到三个IEnumerable接口派生类的实例作为团结的值(全数可被迭代遍历的聚众都落实了那一个接口,包罗数组、List<T>等)。种种ItemControl都独具温馨的条文容器Item Container,例如,ListBox的条目容器是ListBoxItem、Combox的条目容器是ComboxItem。ItemSource里面保存的是一条一条的数目,想要把数量体现出来就要为数量穿上国外国语高校衣,条目容器就起到了数据外衣的效果。那样将数据外衣和它所对应的条目容器关联起来呢?当然时依靠Binding!只要我们为一个ItemControl设置了ItemSource属性值,ItemControl会自行迭代当中的数量成分,为每一个数据元素准备多个条目容器,并动用Binding成分在条款容器和数量成分之间创立起涉嫌,让大家来看七个例证:

UI代码如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window8″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window8″ Height=”356″ Width=”471″>  
  5.     <Grid>  
  6.         <StackPanel Height=”295″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”427″>  
  7.             <TextBlock Height=”23″ Name=”textBlock1″ Text=”学员编号:” />  
  8.             <TextBox Height=”23″ Name=”txtStudentId” Width=”301″ HorizontalAlignment=”Left”/>  
  9.             <TextBlock Height=”23″ Name=”textBlock2″ Text=”学员列表:” />  
  10.             <ListBox Height=”208″ Name=”lbStudent” Width=”305″ HorizontalAlignment=”Left”/>  
  11.         </StackPanel>  
  12.     </Grid>  
  13. </Window>  

 

窗体运营作效果果如下图:

图片 50

大家要落到实处的功用正是把List<Student>的汇合作为ListBox的ItemSource,让ListBox展现学员的Name,并利用TextBox呈现当前相中学员的Id,为了兑现这些职能,大家要求在窗体的构造函数中增加几行代码:

 

[csharp] view
plain
 copy

 

 print?

  1. List<Student> infos = new List<Student>() {   
  2.             new Student(){ Id=1, Age=11, Name=”Tom”},  
  3.             new Student(){ Id=2, Age=12, Name=”Darren”},  
  4.             new Student(){ Id=3, Age=13, Name=”Jacky”},  
  5.             new Student(){ Id=4, Age=14, Name=”Andy”}  
  6.             };  
  7.             this.lbStudent.ItemsSource = infos;  
  8.             this.lbStudent.DisplayMemberPath = “Name”;  
  9.   
  10.             this.txtStudentId.SetBinding(TextBox.TextProperty,new Binding(“SelectedItem.Id”){ Source=lbStudent});  

运作结果如下图:

 

**图片 51

您可能回看,那一个事例中并从未出现刚才大家说的Binding。实际上, this.lbStudent.DisplayMemberPath

“Name”;那点代码暴露了好几马迹蛛丝。注意到含有Path这一个单词了吧?那证明它是三个路线。当DisplayMemberPath
被赋值未来,ListBox在收获ItemSource的时候就会创建2个等量的ListBoxItem并以DisplayMemberPath的值为Path创设Binding,Binding的目的是ListBoxItem的剧情插件(实际上是2个TextBox,下边就会看见)。**

如过在ItemControl类的代码里刨根问底,你会发现Binding的进程是在DisplayMemberTemplateSelector类的SelectTemplate方法里达成的。这一个主意的定义格式如下:

 

[csharp] view
plain
 copy

 

 print?

  1. public override DataTemplate SelectTemplate(object item, DependencyObject container)  
  2.         {  
  3.             //逻辑代码  
  4.         }  

那里我们倒不用关注它的其实内容,注意到它的重回值没有,是2个DataTemplate类型的值。数据的外衣正是由DataTemplate穿上的!当大家尚无为ItemControl展现的钦点Template的时候SelectTemplate会暗许的为大家创制二个最简便易行的DataTemplate—-就恍如给多少穿上了三个简约的服装一样。至于怎样是Template以及那几个主意的完全代码将会停放与Template相关的篇章中精心去研讨。那里大家只关注SelectTemplate内部创建Binding
的几行紧要代码:

 

 

[csharp] view
plain
 copy

 

 print?

  1. FrameworkElementFactory text = ContentPresenter.CreateTextBlockFactory();  
  2.            Binding bind = new Binding();  
  3.            bind.Path = new PropertyPath(_displayMemberPath);  
  4.            bind.StringFormat = _stringFormat;  
  5.            text.SetBinding(TextBlock.TextProperty,bind);  

注意:

 

那里对新成立的Binding设定了Path而从不点名Source,紧接这就把它涉及到了TextBlock上。显明,要想博得Source,这些Binding必要向树根方向查找包涵_displayMemberPath钦赐属性的DataContext。

**最终大家再看四个出示为数据设置DataTemplate的例证,先把C#代码中的this.lbStudent.DisplayMemberPath

“Name”;一句删除,再在XAML代码中添加几行代码,ListBox的ItemTemplate属性(继承自ItemControl类)的品种是DataTemplate,上边我们就为Student类型实例量身定做“衣裳”。**

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window8″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window8″ Height=”356″ Width=”471″>  
  5.     <Grid>  
  6.         <StackPanel Height=”295″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”stackPanel1″ VerticalAlignment=”Top” Width=”427″>  
  7.             <TextBlock Height=”23″ Name=”textBlock1″ Text=”学员编号:” />  
  8.             <TextBox Height=”23″ Name=”txtStudentId” Width=”301″ HorizontalAlignment=”Left”/>  
  9.             <TextBlock Height=”23″ Name=”textBlock2″ Text=”学员列表:” />  
  10.             <ListBox Height=”208″ Name=”lbStudent” Width=”305″ HorizontalAlignment=”Left”>  
  11.                 <ListBox.ItemTemplate>  
  12.                     <DataTemplate>  
  13.                         <StackPanel Name=”stackPanel2″ Orientation=”Horizontal”>  
  14.                             <TextBlock  Text=”{Binding Id}” Margin=”5″ Background=”Beige”/>  
  15.                             <TextBlock Text=”{Binding Name}” Margin=”5″/>  
  16.                             <TextBlock  Text=”{Binding Age}” Margin=”5″/>  
  17.                         </StackPanel>  
  18.                     </DataTemplate>  
  19.                 </ListBox.ItemTemplate>  
  20.             </ListBox>  
  21.               
  22.         </StackPanel>  
  23.     </Grid>  
  24. </Window>  

运作效果图:

 

图片 52

最终越发提示我们一点:

在行使集合类型的数目作为列表控件的ItemSource时一般会考虑采纳ObservableCollection<T>替换List<T>,因为ObservableCollection<T>类完成了INotifyChange和INotifyPropertyChanged接口,能把集合的浮动及时文告彰显到它的列表控件上,改变会即时展现出来。

 

1.3.8    
使用ADO.net指标作为Binding的源

在.Net开发工作中,大家用ADO.Net类对数据库实行操作。常见的行事就是从数据库中读取数据到DataTable中,在把DataTable里的数码绑定的UI的控件里面(如成绩单、博客列表)。纵然在风行的软件架构中并不把DataTable中的数据间接体今后UI列表控件里面而是先经过LINQ等手段把DataTable里的数码转换到伏贴的用户自定义类型集合,但WPF也支撑DataTable也支撑在列表控件和DataTable里直接建立Binding。

明日大家做一个实例来讲学怎么着在DataTable和UI建立Binding:

大部情状下大家会用ListView控件来体现多少个DataTable,XAML代码如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window9″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window9″ Height=”345″ Width=”482″>  
  5.     <StackPanel Height=”279″ Name=”stackPanel1″ Width=”431″>  
  6.         <ListView Height=”247″ Name=”listView1″ Width=”376″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                      
  10.                         <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding Id}” Width=”60″>  
  11.                               
  12.                         </GridViewColumn>  
  13.                         <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding Name}” Width=”60″>  
  14.   
  15.                         </GridViewColumn>  
  16.                         <GridViewColumn Header=”Age” DisplayMemberBinding=”{Binding Age}” Width=”60″>  
  17.   
  18.                         </GridViewColumn>  
  19.                         <GridViewColumn Header=”Sex” DisplayMemberBinding=”{Binding Sex}” Width=”60″>  
  20.   
  21.                         </GridViewColumn>  
  22.                       
  23.                 </GridView>  
  24.             </ListView.View>  
  25.         </ListView>  
  26.     </StackPanel>  
  27. </Window>  

此间我们有几点需求留意的地点:

 

从字面上来精晓,ListView和GridView应该属于同一流其余控件,实际上并未如此!ListView是ListBox的派生类而GridView是ViewBase的派生类,ListView中的View是二个ViewBase对象,所以,GridView能够做为ListView的View来使用而无法同日而语独立的控件来使用。那里运用理念是构成形式,即ListView有1个View,可是至于是GridView照旧别的品类的View,由程序员自个儿选取—-近来唯有1个GridView可用,推断微软在此间还会有增加。其次,GridView的内容属性是Columns,这几个性子是GridViewColumnCollection类型对象。因为XAML支持对情节属性的简写,能够简单<GridView.Columns>这层标签,直接在GridView的情节部分概念2个<GridViewColumn>对象,GridViewColumn中最要紧的3个个性是DisplayBinding(类型是BindingBase),使用那性子情能够钦点这一列使用什么的Binding去关联数据——那与ListBox有点分裂,ListBox使用的是DisplayMemberPath属性(类型是string)。假若想用更扑朔迷离的构造来代表这一标题或数量,则可为GridViewColumn设置HeadTemplate和CellTemplate,它们的档次都以DataTemplate。

运作效果如下:

图片 53

后台代码如下:

 

[csharp] view
plain
 copy

 

 print?

  1. public Window9()  
  2.        {  
  3.            InitializeComponent();  
  4.            DataTable dtInfo = CreateDataTable();  
  5.            for (int i = 0; i < 10; i++)  
  6.            {  
  7.                DataRow dr = dtInfo.NewRow();  
  8.                dr[0] = i;  
  9.                dr[1] = “猴王” + i;  
  10.                dr[2] = i + 10;  
  11.                dr[3] = “男”;  
  12.                dtInfo.Rows.Add(dr);  
  13.            }  
  14.    
  15.            this.listView1.ItemsSource = dtInfo.DefaultView;  
  16.        }  
  17.   
  18.   
  19.        private DataTable CreateDataTable()  
  20.        {  
  21.            DataTable dt = new DataTable(“newtable”);  
  22.              
  23.            DataColumn[] columns = new DataColumn[]{new DataColumn(“Id”),new DataColumn(“Name”),new DataColumn(“Age”),new DataColumn(“Sex”)};  
  24.            dt.Columns.AddRange(columns);  
  25.            return dt;  
  26.        }  

透过上面包车型大巴例证大家早就知晓DataTable的DefaultView能够做为ItemSource来使用,拿DataTable直接用行吗,让大家摸索看:

 

 

[csharp] view
plain
 copy

 

 print?

  1. InitializeComponent();  
  2.            DataTable dtInfo = CreateDataTable();  
  3.            for (int i = 0; i < 10; i++)  
  4.            {  
  5.                DataRow dr = dtInfo.NewRow();  
  6.                dr[0] = i;  
  7.                dr[1] = “猴王” + i;  
  8.                dr[2] = i + 10;  
  9.                dr[3] = “男”;  
  10.                dtInfo.Rows.Add(dr);  
  11.            }  
  12.    
  13.            this.listView1.ItemsSource = dtInfo;  

编写翻译的时候系统会报错提醒:

 

错误
 1无法将品种“System.Data.DataTable”隐式转换为“System.Collections.IEnumerable”。存在多少个显式转换(是或不是贫乏强制转换?)d:\本人的文书档案\visual
studio
2010\Projects\WpfApplication2\WpfApplication1\Window9.xaml.cs3642WpfApplication1

分明DataTable不能够一贯拿来为ItemSource赋值。不过,当您把DataTable对象放在叁个对象的Context属性的时候,并把三个ItemSource与三个既没有点名Source又尚未点名Path的Binding绑定起来的时候,Binding却能活动找到它的DefaultView并当作本身的Source来使用:

 

[csharp] view
plain
 copy

 

 print?

  1. DataTable dtInfo = CreateDataTable();  
  2.             for (int i = 0; i < 10; i++)  
  3.             {  
  4.                 DataRow dr = dtInfo.NewRow();  
  5.                 dr[0] = i;  
  6.                 dr[1] = “猴王” + i;  
  7.                 dr[2] = i + 10;  
  8.                 dr[3] = “男”;  
  9.                 dtInfo.Rows.Add(dr);  
  10.             }  
  11.   
  12.             this.listView1.DataContext = dtInfo;  
  13.             this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  

因而,如果您在代码中发觉把DataTable而不是DefaultView作为DataContext值,并且为ItemSource设置3个既无Path又从不Source的Binding的时候,千万别感觉到可疑。

 

1.3.9        使用XML数据作为Binding的源

迄今截止,.NETFramWork提供了两套处理XML数据的类库:

顺应DOM(Document Object
Modle,文书档案对象模型)标准类库:包含XmlDocument、XmlElement、XmlNode、XmlAttribute等类。那套类库的风味是中规中矩,成效强大,但也背负了太多了XML的思想意识和复杂。

以LINQ(Language-Intergrated
Query,语言集成查询)为底蕴的类库:包罗XDocument,XElement,XNode,XAttribute等类。那套类库的表征是足以经过LINQ举办询问和操作,方便急速。

下边我们重点教师一下正经项指标类库,基于LINQ的查询大家身处下一节探讨。

如今先后设计只要涉及到长途传输就离不开XML,因为大多数数额传输是依照SOAP(Simple
Object Access
Protocol,不难对象访问协议)相关文书档案协议,而SOAP又是将指标连串化为XML文本实行传输。XML文本是树形结构的,所以XML能够方便的用来表示线性集合(如Array、List等)和树形结构数据。

注意:

在行使XML数据作为Binding的Source的时候大家将动用XPath属性而不是Path属性来钦定数量的源于。

作者们先看一个线性集合的例证。上边包车型地铁XML文本是一组文本信息,大家要把它呈现在3个ListView控件里:

 

[html] view
plain
 copy

 

 print?

  1. <?xml version=”1.0″ encoding=”utf-8″ ?>  
  2. <StudentList>  
  3.   <Student id=”1″>  
  4.     <Name>Andy</Name>  
  5.   </Student>  
  6.   <Student id=”2″>  
  7.     <Name>Jacky</Name>  
  8.   </Student>  
  9.   <Student id=”3″>  
  10.     <Name>Darren</Name>  
  11.   </Student>  
  12.   <Student id=”4″>  
  13.     <Name>DK</Name>  
  14.   </Student>  
  15.   <Student id=”1″>  
  16.     <Name>Jim</Name>  
  17.   </Student>  
  18. </StudentList>  

对应的XAML如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window10″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window10″ Height=”397″ Width=”485″>  
  5.     <StackPanel Width=”409″ Height=”331″ Background=”LightBlue”>  
  6.         <ListView Height=”302″ Name=”listView1″ Width=”396″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                     <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding XPath=@id}” Width=”80″>  
  10.                           
  11.                     </GridViewColumn>  
  12.                     <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding XPath=Name}” Width=”150″>  
  13.   
  14.                     </GridViewColumn>  
  15.                 </GridView>  
  16.             </ListView.View>  
  17.         </ListView>  
  18.     </StackPanel>  
  19. </Window>  

C#代码如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. private void BindingInfo()  
  2. {  
  3.     XmlDocument doc = new XmlDocument();  
  4.     doc.Load(@”d:\自家的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  5.   
  6.     XmlDataProvider dp = new XmlDataProvider();  
  7.     dp.Document = doc;  
  8.   
  9.     dp.XPath = @”StudentList/Student”;  
  10.     this.listView1.DataContext = dp;  
  11.     this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  
  12. }  

程序运转效果如下:

 

**图片 54

**

XMLDataProvider还有一个名为Source的属性,能够一直用它钦赐XML文书档案所在地方(无论是XML文书档案是储存在本地硬盘还是互连网地方),所以,后台代码也足以写成如下:

 

[csharp] view
plain
 copy

 

 print?

  1. private void BindingInfo()  
  2.         {  
  3.             //XmlDocument doc = new XmlDocument();  
  4.             //doc.Load(@”d:\自作者的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  5.   
  6.             XmlDataProvider dp = new XmlDataProvider();  
  7.             dp.Source = new Uri(@”d:\本身的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml”);  
  8.            // dp.Document = doc;  
  9.   
  10.             dp.XPath = @”StudentList/Student”;  
  11.             this.listView1.DataContext = dp;  
  12.             this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());  
  13.         }  

XAML最器重的两句:DisplayMemberBinding=”{Binding
XPath=@id}”和DisplayMemberBinding=”{Binding
XPath=Name}”,他们分别为GridView两列钦命了要关心的XML路径—-很明显,使用@符号加字符串表示的是XML成分的Attribute,不加@符号表示的是子级元素。

 

XML语言可以便宜的表示树形数据结构,下边包车型客车例子是使用TreeView控件来体现全体多少层目录的文件系统,而且,此次把XML数据和XMLDataProvider对象直接写在XAML里面,代码中用到了HierarchicalDataTemplate类,这么些类具有ItemsSource属性,可知由那种Template展现的多少是足以有子级集合的。代码如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window11″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window11″ Height=”349″ Width=”545″>  
  5.     <Window.Resources>  
  6.         <XmlDataProvider x:Key=”xdp” XPath=”FileSystem/Folder”>  
  7.             <x:XData>  
  8.                 <FileSystem xmlns=””>  
  9.                     <Folder Name=”Books”>  
  10.                         <Folder Name=”Programming”>  
  11.                             <Folder Name=”Windows”>  
  12.                                 <Folder Name=”WPF”>  
  13.                                    
  14.                                 </Folder>  
  15.                                 <Folder Name=”Winform”>  
  16.   
  17.                                 </Folder>  
  18.                                 <Folder Name=”ASP.NET”>  
  19.   
  20.                                 </Folder>  
  21.                             </Folder>  
  22.                         </Folder>  
  23.                     </Folder>  
  24.                     <Folder Name=”Tools”>  
  25.                         <Folder Name=”Development”/>  
  26.                         <Folder Name=”Designment”/>  
  27.                         <Folder Name=”Players”/>  
  28.                     </Folder>  
  29.                 </FileSystem>  
  30.             </x:XData>  
  31.         </XmlDataProvider>  
  32.     </Window.Resources>  
  33.     <Grid>  
  34.         <TreeView Height=”283″ HorizontalAlignment=”Left”  Name=”treeView1″ VerticalAlignment=”Top” Width=”511″ ItemsSource=”{Binding Source={StaticResource ResourceKey=xdp}}”>  
  35.             <TreeView.ItemTemplate>  
  36.                 <HierarchicalDataTemplate ItemsSource=”{Binding XPath=Folder}”>  
  37.                     <TextBlock Height=”23″ HorizontalAlignment=”Left”  Name=”textBlock1″ Text=”{Binding XPath=@Name}” VerticalAlignment=”Top” />  
  38.                 </HierarchicalDataTemplate>  
  39.             </TreeView.ItemTemplate>  
  40.         </TreeView>  
  41.           
  42.     </Grid>  
  43. </Window>  

注意:

 

将XmlDataProvider直接写在XAML代码里面,那么她的数码须要放在<x:XData>标签中。

由于本例子设计到了StaticResource和HierarchicalDataTemplate,都在此以前边的内容,相对相比较难懂,等学习完后边的Resource和Template章节从此再回到便会了解于胸。

程序运维效果如下图:

图片 55

1.3.10      使用LINQ检索结果做为Binding 的源

至3.0版本开头,.NET Framework开首帮助LINQ(Language-Intergrated Query
 
语言集成查询),使用LINQ,大家能够便宜的操作集合对象、DataTable对象和XML对象不必动辄不动把有个别层foreach循环嵌套在一齐却只是为着达成二个很简短的天职。

LINQ查询的结果是二个IEnumerable<T>类型对象,而IEnumerable<T>又派生自IEnumerable,所以它可以视作列表控件的ItemsSource来使用。

先创设一个名为Student的类:

 

[csharp] view
plain
 copy

 

 print?

  1. public class Student  
  2.   {  
  3.       public int Id { get; set; }  
  4.       public string Name { get; set; }  
  5.       public int Age { get; set; }  
  6.   }  

XAML代码如下:

 

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window12″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window12″ Height=”372″ Width=”538″>  
  5.     <Grid>  
  6.         <ListView Height=”311″ HorizontalAlignment=”Left” Margin=”10,10,0,0″ Name=”listView1″ VerticalAlignment=”Top” Width=”494″>  
  7.             <ListView.View>  
  8.                 <GridView>  
  9.                     <GridViewColumn Header=”ID” DisplayMemberBinding=”{Binding Id}” Width=”100″/>  
  10.                     <GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding Name}” Width=”100″/>  
  11.                     <GridViewColumn Header=”Age” DisplayMemberBinding=”{Binding Age}” Width=”100″/>  
  12.                 </GridView>  
  13.             </ListView.View>  
  14.         </ListView>  
  15.     </Grid>  
  16. </Window>  

 

 

后台代码如下:

[csharp] view
plain
 copy

 

 print?

  1. private void BindingData()  
  2.         {  
  3.             List<Student> infos = new List<Student>()  
  4.             {  
  5.                 new Student(){Id=1, Age=29, Name=”Tim”},  
  6.                  new Student(){Id=1, Age=28, Name=”Tom”},  
  7.                   new Student(){Id=1, Age=27, Name=”Kyle”},  
  8.                    new Student(){Id=1, Age=26, Name=”Tony”},  
  9.                     new Student(){Id=1, Age=25, Name=”Vina”},  
  10.                      new Student(){Id=1, Age=24, Name=”Mike”}  
  11.             };  
  12.             this.listView1.ItemsSource = from stu in infos where stu.Name.StartsWith(“T”) select stu;  
  13.         }  

要是数量存放在八个DataTable对象里面,则后台代码如下:

 

[csharp] view
plain
 copy

 

 print?

  1. private void BindingDataByDataTable()  
  2.        {  
  3.            DataTable dtInfo = CreateDataTable();  
  4.            this.listView1.ItemsSource = from row in dtInfo.Rows.Cast<DataRow>()  
  5.                                         where Convert.ToString(row[“Name”]).StartsWith(“T”)  
  6.                                         select new Student()  
  7.                                         {  
  8.                                             Id = Convert.ToInt32(row[“Id”]), Name=Convert.ToString(row[“Name”]),Age=Convert.ToInt32(row[“Age”])  
  9.                                         };  
  10.              
  11.        }  

比方数量存款和储蓄在XML里面,存款和储蓄格式如下:

 

 

[html] view
plain
 copy

 

 print?

  1. <?xml version=”1.0″ encoding=”utf-8″ ?>  
  2. <StudentList>  
  3.   <Class>  
  4.     <Student Id=”0″ Age=”29″ Name=”Tim” />  
  5.     <Student Id=”0″ Age=”28″ Name=”Tom” />  
  6.     <Student Id=”0″ Age=”27″ Name=”Mess” />  
  7.   </Class>  
  8.   <Class>  
  9.     <Student Id=”0″ Age=”26″ Name=”Tony” />  
  10.     <Student Id=”0″ Age=”25″ Name=”Vina” />  
  11.     <Student Id=”0″ Age=”24″ Name=”Emily” />  
  12.   </Class>  
  13. </StudentList>  

则代码是这么(注意:xd.Descendants(“Student”)那一个艺术,它能够跨XML的层级):

 

 

[csharp] view
plain
 copy

 

 print?

  1. private void BindingDataByXml()  
  2.         {  
  3.             XDocument xd = XDocument.Load(@”d:\自作者的文书档案\visual studio 2010\Projects\WpfApplication2\WpfApplication1\testDate.xml”);  
  4.   
  5.             this.listView1.ItemsSource = from element in xd.Descendants(“Student”)  
  6.                                          where element.Attribute(“Name”).Value.StartsWith(“T”)  
  7.                                          select new Student()  
  8.                                              {  
  9.                                                  Name = element.Attribute(“Name”).Value,  
  10.                                                  Id = Convert.ToInt32(element.Attribute(“Id”).Value),  
  11.                                                  Age = Convert.ToInt32(element.Attribute(“Age”).Value)  
  12.                                              };  
  13.         }  

 

 

程序运维效果如下图:

**图片 56

**

1.3.11    使用ObjectDataProvider作为binding的Source

精粹状态下,上游程序员将类设计好、使用品质把数量暴表露来,下游程序员将那些类作为Binding的Source、把品质作为Binding的Path来消费这个类。但很难保险1个类的性质都用属性暴流露来,比如大家需求的数额或然是办法的重临值。而重新规划底层类的危害和开销会比较高,况且黑盒引用类库的意况下咱们不容许改变已经编写翻译好的类,那时候需求选用ObjectDataProvider来包装做为Binding源的数量对象了。

ObjcetDataProvider
顾名思义正是把对指标作为数据源提必要Binding。后边还论及过XmlDataProvider,那七个类的父类都以DataSourceProvider抽象类。

前日有二个名为Calculator的类,它具有加、减、乘、除的措施:

 

[csharp] view
plain
 copy

 

 print?

  1. public class Caculate  
  2. {  
  3.     public string Add(string arg1,string arg2)  
  4.     {  
  5.         double x = 0;  
  6.         double y = 0;  
  7.         double z = 0;  
  8.         if(double.TryParse(arg1,out x)&&double.TryParse(arg2,out y))  
  9.         {  
  10.             z = x + y;  
  11.             return z.ToString();  
  12.         }  
  13.         return “Iput Error”;  
  14.     }  
  15.   
  16.     //其余方法简便  
  17. }  

大家先写叁个非凡简单的小例子来打探下ObjectDataProvider类。随便新建三个WPF窗体,窗体内拖放一个控件,控件的Click事件如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. private void button1_Click(object sender, RoutedEventArgs e)  
  2.      {  
  3.          ObjectDataProvider odp = new ObjectDataProvider();  
  4.          odp.ObjectInstance = new Caculate();  
  5.          odp.MethodName=”Add”;  
  6.          odp.MethodParameters.Add(“100”);  
  7.          odp.MethodParameters.Add(“200”);  
  8.          MessageBox.Show(odp.Data.ToString());  
  9.   
  10.      }  

运营程序,单击button大家会看出如下界面:

 

图片 57

通过这几个程序大家能够明白到ObjectDataProvider对象和它被打包的靶子关系如下图:

图片 58

 

刺探了ObjectDataProvider的施用方法,大家看看哪些把它当作Binding的Source来使用。程序的XAML代码和截图如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window14″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window14″ Height=”202″ Width=”345″>  
  5.     <StackPanel Background=”LightBlue”>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  7.         <TextBox Height=”23″ Name=”textBox2″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  8.         <TextBox Height=”23″ Name=”textBox3″ Width=”200″ HorizontalAlignment=”Left” Margin=”15″/>  
  9.     </StackPanel>  
  10. </Window>  

图片 59

 

以此程序达成的功能是,笔者在前四个TextBox里面输入值的时候,第6个TextBox会呈现前七个文本框里面相加之和。把代码写在三个名为SetBinding的方法里面,然后在窗体的构造器里面调用这几个艺术:

 

[csharp] view
plain
 copy

 

 print?

  1. private void SetBinding()  
  2.        {  
  3.            ObjectDataProvider objpro = new ObjectDataProvider();  
  4.            objpro.ObjectInstance = new Caculate();  
  5.            objpro.MethodName = “Add”;  
  6.            objpro.MethodParameters.Add(“0”);  
  7.            objpro.MethodParameters.Add(“0”);  
  8.            Binding bindingToArg1 = new Binding(“MethodParameters[0]”) { Source=objpro,BindsDirectlyToSource=true, UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged};  
  9.            Binding bindingToArg2 = new Binding(“MethodParameters[1]”) { Source=objpro,BindsDirectlyToSource=true,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};  
  10.            Binding bindToResult = new Binding(“.”) { Source=objpro};  
  11.            this.textBox1.SetBinding(TextBox.TextProperty, bindingToArg1);  
  12.            this.textBox2.SetBinding(TextBox.TextProperty, bindingToArg2);  
  13.            this.textBox3.SetBinding(TextBox.TextProperty,bindToResult);  
  14.        }  

让大家先来分析一下上边两段代码,前边说过,ObjectDataProvider类的法力是包裹二个以艺术揭穿数据的对象,那里我们先创建了一个ObjectDataProvider的目的,然后用贰个Caculate对象为其ObjectInstance对象赋值—那就把叁个Caculate对象包装在了ObjectDataProvider里面。还有此外二个方法来创制棉被服装进的指标,那就是报告包装对象被包裹对象的品类和期望调用的构造器,让ObjectDataProvider自身来创制对象,代码大致是这么:

 

 

[csharp] view
plain
 copy

 

 print?

  1. //—  
  2.            objpro.ObjectInstance = typeof(Caculate);  
  3.            objpro.ConstructorParameters.Add(arg1);  
  4.            objpro.ConstructorParameters.Add(arg2);  
  5.            //—-  

因为在XAML中成立对象比较费心,可读性差,所以我们一般会在XAML代码中选择那种钦点项目和构造器的法子。

 

随即,我们运用MethodName属性钦命要调用的Caculator对象中名为Add的艺术—难点又来了,假诺Caculator有几个构造器参数的不二法门Add应该怎么着区分?大家明白,重载方法的区别在于参数列表,紧接着两句正是向MethodParameter属性里面参与八个string类型的参数,那就一定于告诉ObjectDataProvider对象去调用Caculator对象中有所七个string类型参数的Add方法,换句话说,MethodParameter对于参数的反馈是那几个灵动的。

准备好数据源之后,我们准备开创Binding。前面大家已经讲过使用索引器作为Binding的Path,第3个Binding它的Source是3个ObjectDataProvider对象,帕特h是ObjectDataProvider中MethodParameters所引用的首先个因素。BindsDirectlyToSource那句话是报告Binding只是将UI上的值传递给源而不是被ObjectDataProvider包装的Caculator,同时UpdateSourceTrigger设置为UI只要一有浮动就立异Source。第三个Binding只是对第一个的翻版,只是把Path属性指向了第三个成分。第⑨个binding依旧采用ObjectDataProvider作为Source,但使用“.”作为Path—-前边讲过,当数据源本人正是数额的时候就用“.”来做为Path,在XAML中”.”能够不写。

注意:

在ObjectDataProvider对象作为Binding的Source的时候,这一个指标自我就象征了数量,所以那边的Path使用的“.”,而不是Data属性。

末段几行正是将Binding对象关系到2个TextBox对象上。程序运营效果如下:

图片 60

诚如景况下多少从那里来,哪个地方正是Binding的Source,数据到哪个地方去,哪儿便是Binding
的Target。按这些理论,前几个TextBox应该是ObjcetDataProvider的源,而ObjcetDataProvider对象又是终极贰个Text博克斯的源。但实际,四个TextBox都是ObjcetDataProvider作为数据源,只是前四个在数码流向上做了限定,这样做的原委除了有四个:

壹 、ObjcetDataProvider的MethodParameter不是依赖属性,无法看做Binding的对象。

贰 、数据驱动UI理念须要大家尽量的运用数据对象作为Binding的Source而把UI当做Binding的Target。

1.3.12    使用Binding的RelativeSource

当三个Binding有强烈的来自的时候,大家能够通过Source也许ElementName赋值的艺术让Binding与之提到。某个时候我们无法鲜明作为Source对象叫什么名字,可是我们理解它与做为Binding指标对象在UI上的绝对关系,比如控件本人涉嫌自个儿的某部数据,关联自身某级容器的多少,那时候就须要用到Binding的RelativeSource属性。

RelativeSource属性的品类是RelativeSource类,通过那些类的多少个静态只怕非静态的属性大家能够控制它寻找相对数据源的不二法门。请看上边那段代码:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window15″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window15″ Height=”375″ Width=”516″>  
  5.     <Grid Background=”Red” Margin=”10″ x:Name=”gd1″>  
  6.         <DockPanel x:Name=”dp1″ Margin=”10″ Background=”Orange”>  
  7.             <Grid Background=”Yellow” Margin=”10″ x:Name=”gd2″>  
  8.                 <DockPanel Name=”dp2″ Margin=”10″ Background=”LawnGreen”>  
  9.                     <TextBox  Name=”textBox1″  Margin=”10″ FontSize=”24″/>  
  10.                 </DockPanel>  
  11.             </Grid>  
  12.         </DockPanel>  
  13.     </Grid>  
  14. </Window>  

界面运营结果如下:

 

图片 61

小编们把TextBox的Text属性关联到外围容器的Name属性上。在窗体的构造器里面添加如下几行代码:

 

[csharp] view
plain
 copy

 

 print?

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);  
  2.            rs.AncestorLevel = 1;  
  3.            rs.AncestorType = typeof(Grid);  
  4.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  5.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

或在XAML代码中插入等效代码:

 

 

[html] view
plain
 copy

 

 print?

  1. <TextBox  Name=”textBox1″  Margin=”10″ FontSize=”24″ Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Grid},AncestorLevel=1}}”/>  

AncestorLevel属性钦命的是以Binding目的控件为源点的层级偏移量—gd2的偏移量是1,gd2的偏移量是2,依次类推。AncestorType属性告诉Binding去找哪些项目标指标作为团结的源,不是以此项指标靶子会被跳过。上边那段代码的情致是告诉Binding从友好的率先层依次向外找,找到第②个Grid类型对象后把它作为本身的源。运维效果如下图:

 

图片 62
若果把代码改成如下那样:

 

[csharp] view
plain
 copy

 

 print?

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);  
  2.            rs.AncestorLevel = 2;  
  3.            rs.AncestorType = typeof(DockPanel);  
  4.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  5.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

要么把XAML代码改成如下:

 

 

[html] view
plain
 copy

 

 print?

  1. Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DockPanel},AncestorLevel=2}}”  

运行作效果果如下:

 

图片 63

假设TextBox要求关联自个儿的Name属性,那么代码应该这么写:

 

[csharp] view
plain
 copy

 

 print?

  1. RelativeSource rs = new RelativeSource(RelativeSourceMode.Self);  
  2.             
  3.            Binding bind = new Binding(“Name”) { RelativeSource = rs };  
  4.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  

相应的XAML代码如下:

 

 

[html] view
plain
 copy

 

 print?

  1. Text=”{Binding Path=Name, RelativeSource={RelativeSource Mode=Self}}”  

运维效果如下图:

 

图片 64

RelativeSource类的Mode属性是RelativeSourceMode枚举,它的值有:PriviousData、TemplatedParent、Self和FindAncestor。RelativeSource还有三个静态属性:PriviousData、Self、TemplatedParent,它们的类型是RelativeSource类。实际上那二个静态属性正是创办一个RelativeSource的实例、把实例的Mode设置为相呼应的值,然后回到那么些实例。之所以准备那一个静态属性是为了在XAML代码里面一直获得RelativeSource实例。

在DataTemplate中常常用到那那二个静态属性,学习DataTemplate的时候请留意它们的行使办法。

1.4      binding对数码的更换和校验

前方大家曾经知道Binding的意义正是架在Source和Target之间的桥梁,数据足以在那座大桥的声援下去流通。就像现实社会中桥梁需求安装安全检查和关卡一样,Binding那座桥上也能够设置关卡对数码进行求证,不仅如此,假设Binding两端须求不一样的数据类型的时候我们还足以为数量设置转换器。

Binding用于数据有效性校验的卡子是她的ValidationRules属性,用于数据类型转换的关卡是它的Convert属性。

1.4.1          Binding的数目校验

Binding的ValidationRules属性是Collection<ValidationRule>,从它的名号和数据类型大家可以识破能够为每一种Binding设置七个数据校验条件,每个条件是一个ValidationRule对象。ValidationRule是2个抽象类,在行使的时候大家必要创制它的派生类并落到实处它的Validate方法的再次回到值是ValidateionResult类型对象,假若经过认证,就把ValidateionResult对象的IsValidate属性设为true,反之,则必要将IsValidate设置为false并为其ErrorContent属性设置贰个适度的音信内容(一般是字符串)。

上边这么些程序的UI绘制二个TextBox和多个Slider,然后在后台C#代码中创造Binding把它们关联起来—-
已Slide为源,TextBox为对象。Slider的取值范围是0~100,约等于说大家必要验证TextBox中输入的值是否在0~100之间。

次第的XAML部分如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window16″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window16″ Height=”300″ Width=”300″>  
  5.     <StackPanel Background=”AliceBlue” Margin=”10″>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Width=”200″ Margin=”20″/>  
  7.         <Slider Height=”23″ Name=”slider1″ Width=”219″ Maximum=”100″ />  
  8.     </StackPanel>  
  9. </Window>  

为了举办校验,我们准备一个ValidationRule的派生类,内容如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. public class RangeValidationRule : ValidationRule  
  2. {  
  3.   
  4.     public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)  
  5.     {  
  6.         double d = 0;  
  7.         if(double.TryParse(value.ToString(),out d))  
  8.         {  
  9.             if(d>=0&&d<=100)  
  10.             {  
  11.                 return new ValidationResult(true,null);  
  12.             }  
  13.         }  
  14.         return new ValidationResult(false,”ErrorContent”);  
  15.     }  
  16. }  

然后在窗体里面建立Binding:

 

 

[csharp] view
plain
 copy

 

 print?

  1. public Window16()  
  2.        {  
  3.            InitializeComponent();  
  4.            Binding bind =new Binding(“Value”) { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};  
  5.            ValidationRule rule = new RangeValidationRule();  
  6.            rule.ValidatesOnTargetUpdated = true;  
  7.            bind.ValidationRules.Add(rule);  
  8.   
  9.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  10.        }  

成功后运维程序,当输入0~100里边的值的时候程序平常突显,然而输入区间之外的值的时候TextBox会展现为镉黄边框,表示值是大错特错的,不能够传值给Source。效果如下图:

 

图片 65图片 66

先把Silider的取值范围从0~100改为-100~200:

图片 67图片 68

你只怕回看,在印证错误的时候,ValidationResult会引导一条错误消息,那么哪些接纳那条错误新闻呢?想要用到那或多或少,须要选用前边会详细讲解到的知识—–路由事件(Routed
伊芙nt)。

先是在创建Binding
的时候要把Binding的靶子的NotifyOnValidationError属性设置为true,那样,当数码校验战败的时候Binding就像是报告警方器一样爆发一个信号。这几个信号会在已Binding对象的Target为源点的UI树上进行传播。信号没到达3个节点,借使这几个节点设置了对那种信号的侦听器(事件处理器),那么那么些侦听器就会被触发并处理那几个信号,信号处理实现后,还可以是或不是让信号继续沿着UI树向上传播—那便是路由事件。信号在UI树上传递的经过称为路由(Route)。

建立Binding的代码如下:

 

[csharp] view
plain
 copy

 

 print?

  1. public Window16()  
  2.        {  
  3.            InitializeComponent();  
  4.            Binding bind =new Binding(“Value”) { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};  
  5.            ValidationRule rule = new RangeValidationRule();  
  6.            rule.ValidatesOnTargetUpdated = true;  
  7.            bind.ValidationRules.Add(rule);  
  8.            bind.NotifyOnValidationError = true;  
  9.            this.textBox1.SetBinding(TextBox.TextProperty, bind);  
  10.            this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));  
  11.        }  

用来侦听校验错误事件的轩然大波处理器如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. private void ValidationError(object sender, RoutedEventArgs e)  
  2.         {  
  3.             if (Validation.GetErrors(textBox1).Count > 0)  
  4.             {  
  5.                 this.textBox1.ToolTip = Validation.GetErrors(textBox1)[0].ErrorContent.ToString();  
  6.             }  
  7.             else  
  8.             {  
  9.                 this.textBox1.ToolTip = “”;  
  10.             }  
  11.         }  

程序一旦校验失利,就会选拔ToolTip提醒用户,如下图:

 

图片 69

1.4.2    Binding的多寡转换

后面包车型大巴大队人马事例大家都在应用Binding将TextBox和Slider之间建立关联—-Slider控件作为Source(Path的Value属性),TextBox作为Target(目的属性为Text)。不知晓大家有没有留意到,Slider的Value属性是Double类型值,而TextBox的Text属性是string类型的值,在C#那种强类型语言中却足以来回自如,是怎么回事呢?

原来Binding还有其余一种机制称为数据转换,当Source端钦赐的Path属性值和Target端钦命的对象属性不雷同的时候,大家得以加上数据转换器(DataConvert)。上面我们关系的难题莫过于正是double和stirng类型互相转换的题材,因为拍卖起来比较简单,所以WPF类库就协调帮大家做了,但有些数据类型转换就不是WPF能帮咱们做的了,例如上面包车型客车那种气象:

 

  • Source里面包车型大巴值是Y、N、X八个值(或然是Char类型,string类型也许自定义枚举类型),UI上相应的是CheckBox控件,必要把那三个值映射为它的IsChecked属性值(bool类型)。
  • 当TextBox里面必须输入的有类容时候用于登录的Button才会冒出,那是string类型与Visibility枚举类型或bool类型之间的更换(Binding的Model将是oneway)。
  • Source里面包车型地铁值有或许是Male或FeMale(string或枚举),UI是用以体现图片的Image控件,那时候要求把Source里面值转换为对应的头像图片U奥德赛I(亦是oneway)。

 

当碰到这么些意况,我们只可以协调入手写Converter,方法是开创七个类并让那么些类达成IValueConverter接口,IValueConverter定义如下:

 

[csharp] view
plain
 copy

 

 print?

  1. public interface IValueConverter  
  2. {  
  3.     object Convert(object value, Type targetType, object parameters, CultureInfo culture);  
  4.     object ConvertBack(object value, Type targetType, object parameters, CultureInfo culture);  
  5. }  

当数码从Binding的Source流向Target的时候,Convert方法将被调用;反之ConvertBack将被调用。那四个章程的参数列表一模一样:第一个参数为Object。最大限度的保管了Convert的首要。第一个参数用于鲜明重临参数的回来类型。第八个参数为了将附加的参数字传送入方法,若须求传递多少个消息,则供给将音信做为多个集合传入即可。

 

Binding对象的Mode属性将影响那五个艺术的调用;假诺Mode为TwoWay或Default行为与TwoWay一致则三个方式都有恐怕被调用。假使Mode是OneWay可能Default行为与OneWay一致则唯有Convert方法会被调用。此外意况同理。

上边那几个例子是三个Converter的总结实例,程序的用处是向玩家突显一些军用飞机的场地音讯。

先是创设几个自定义数据类型:

 

[csharp] view
plain
 copy

 

 print?

  1. public enum Category  
  2.    {  
  3.        Bomber,  
  4.        Fighter  
  5.    }  
  6.   
  7.    public enum State  
  8.    {  
  9.        Available,  
  10.        Locked,  
  11.        Unknown  
  12.    }  
  13.   
  14.    public class Plane  
  15.    {  
  16.        public Category category { get; set; }  
  17.        public State state { get; set; }  
  18.        public string name { get; set; }  
  19.    }  

在UI里,Category的情状被映射为图标,那三个图标已经被作者放入项目中,如图:

 

图片 70

并且飞机的State属性在UI里面被映射为CheckBox。因为存在上述三种炫耀关系。大家供给提供三个Converter:二个有Categroy类型单向转换为string类型(XAML会把string解析为图片财富),另叁个是State和bool类型间接的双向转换。代码如下:

 

[csharp] view
plain
 copy

 

 print?

  1. public class CategoryToSourceConverter:IValueConverter  
  2.     {  
  3.   
  4.         public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  5.         {  
  6.             Category category = (Category)value;  
  7.             switch (category)  
  8.             {  
  9.                 case Category.Bomber:  
  10.                     return @”ICONS/Bomber.png”;  
  11.                      
  12.                 case Category.Fighter:  
  13.                     return @”ICONS/Fighter.png”;  
  14.                      
  15.                 default:  
  16.                     return null;  
  17.                       
  18.             }  
  19.         }  
  20.   
  21.         public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  22.         {  
  23.             throw new NotImplementedException();  
  24.         }  
  25.     }  

 

[csharp] view
plain
 copy

 

 print?

  1. public class StateToNullableBoolConverter:IValueConverter  
  2.     {  
  3.   
  4.         public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  5.         {  
  6.             State state = (State)value;  
  7.             switch (state)  
  8.             {  
  9.                 case State.Available:  
  10.                     return true;  
  11.                       
  12.                 case State.Locked:  
  13.                     return false;  
  14.                 case State.Unknown:  
  15.                       
  16.                 default:  
  17.                     return null;  
  18.             }  
  19.         }  
  20.   
  21.         public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)  
  22.         {  
  23.             bool? nb = (bool?)value;  
  24.             switch (nb)  
  25.             {  
  26.                 case true:  
  27.                     return State.Available;  
  28.                 case false:  
  29.                     return State.Locked;  
  30.                 case null:  
  31.                 default:  
  32.                     return State.Unknown;  
  33.                       
  34.             }  
  35.         }  
  36.     }  

上边大家来探望如何在XAML代码里面来费用那一个Converter:

 

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window17″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         xmlns:local=”clr-namespace:WpfApplication1.BLL”  
  5.         Title=”Window17″ Height=”327″ Width=”460″>  
  6.     <Window.Resources>  
  7.         <local:CategoryToSourceConverter x:Key=”cts” />  
  8.         <local:StateToNullableBoolConverter x:Key=”snb” />  
  9.     </Window.Resources>  
  10.     <StackPanel Name=”stackPanel1″ Background=”AliceBlue” Margin=”10″>  
  11.         <ListBox  Name=”listBox1″ Height=”160″ Margin=”5″>  
  12.             <ListBox.ItemTemplate>  
  13.                 <DataTemplate>  
  14.                     <StackPanel Orientation=”Horizontal”>  
  15.                         <Image Height=”16″ Name=”image1″ Stretch=”Fill” Width=”16″ Source=”{Binding Path=category,Converter={StaticResource cts}}”/>  
  16.                         <TextBlock Height=”23″ Name=”textBlock1″ Text=”{Binding name}” Margin=”8,0″ Width=”80″/>  
  17.                         <CheckBox  Height=”16″ Name=”checkBox1″ IsChecked=”{Binding Path=state,Converter={StaticResource snb}}” IsThreeState=”True”/>  
  18.                     </StackPanel>  
  19.                 </DataTemplate>  
  20.             </ListBox.ItemTemplate>  
  21.         </ListBox>  
  22.         <Button Content=”Load” Height=”23″ Name=”button1″ Width=”131″ Margin=”5″ Click=”button1_Click” />  
  23.         <Button Content=”Save” Height=”23″ Name=”button2″ Width=”131″ Margin=”5″ Click=”button2_Click” />  
  24.     </StackPanel>  
  25. </Window>  

Load按钮的事件处理器负责把一组飞机的多寡赋值给ListBox的ItemSource属性,Save的Click事件负责把用户修改过的数据写入文件:

 

 

[csharp] view
plain
 copy

 

 print?

  1. /// <summary>  
  2.         /// Load按钮事件处理器  
  3.         /// </summary>  
  4.         /// <param name=”sender”></param>  
  5.         /// <param name=”e”></param>  
  6.         private void button1_Click(object sender, RoutedEventArgs e)  
  7.         {  
  8.             List<Plane> infos = new List<Plane>() {   
  9.             new Plane(){ category= Category.Bomber,name=”B-1″, state= State.Unknown},  
  10.             new Plane(){ category= Category.Bomber,name=”B-2″, state= State.Unknown},  
  11.             new Plane(){ category= Category.Fighter,name=”F-22″, state= State.Locked},  
  12.             new Plane(){ category= Category.Fighter,name=”Su-47″, state= State.Unknown},  
  13.             new Plane(){ category= Category.Bomber,name=”B-52″, state= State.Available},  
  14.             new Plane(){ category= Category.Fighter,name=”J-10″, state= State.Unknown},  
  15.             };  
  16.             this.listBox1.ItemsSource = infos;  
  17.         }  
  18.         /// <summary>  
  19.         /// Save按钮事件处理器  
  20.         /// </summary>  
  21.         /// <param name=”sender”></param>  
  22.         /// <param name=”e”></param>  
  23.         private void button2_Click(object sender, RoutedEventArgs e)  
  24.         {  
  25.             StringBuilder sb = new StringBuilder();  
  26.             foreach (Plane item in listBox1.Items)  
  27.             {  
  28.                 sb.AppendLine(string.Format(“Categroy={0},State={1},Name={2}”,item.category,item.state,item.name));  
  29.             }  
  30.             File.WriteAllText(@”D:\PlaneList.text”,sb.ToString());  
  31.         }  

运行程序,单击CheckBox修改飞机的State,如图:

 

图片 71图片 72

单击Save后打开D:\\PlaneList.text数据如下图:

图片 73

1.5   MultiBinding(多路Binding)

突发性UI须求体现的数目来源不止3个数量来自决定,那些时候就供给利用MultiBinding,即多路绑定。MultiBinding与Binding一样均以BindingBase为基类,也正是说,凡是能用Binding的场所都能运用MultiBinding。MutiBinding具有一个Bindings的品质,其项目是Connection<BindingBase>,通过这些特性,MultiBinding把一组Binding对象聚合起来,处在那么些Binding结合中的对象可以享有和谐的数量校验和转换机制。它们汇聚起来的数目将2只决定传往MultiBinding指标的数码。如下图:

图片 74

考虑这么2个急需,有二个用以新用户注册的UI(伍个TextBox和2个Button),还有如下一些限制:

 

  • 首先,一个TextBox用于输入用户名,必要数据必须一致。
  • 其三,两个TextBox用于展现输入的信箱,供给数据必须一致。
  • 当TextBox的故事情节全方位符合需要的时候,Button可用。

 

此UI的XAML代码如下:

 

[html] view
plain
 copy

 

 print?

  1. <Window x:Class=”WpfApplication1.Window18″  
  2.         xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.         xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.         Title=”Window18″ Height=”300″ Width=”300″>  
  5.     <StackPanel Name=”stackPanel1″  Margin=”10″ Background=”AliceBlue”>  
  6.         <TextBox Height=”23″ Name=”textBox1″ Margin=”5″ />  
  7.         <TextBox Height=”23″ Name=”textBox2″ Margin=”5″ />  
  8.         <TextBox Height=”23″ Name=”textBox3″ Margin=”5″ />  
  9.         <TextBox Height=”23″ Name=”textBox4″ Margin=”5″ />  
  10.         <Button Content=”Regist” Height=”23″ Name=”btnSubmit” Width=”75″  Margin=”10″/>  
  11.     </StackPanel>  
  12. </Window>  

后台代码如下:

 

 

[csharp] view
plain
 copy

 

 print?

  1. public Window18()  
  2.        {  
  3.            InitializeComponent();  
  4.            SetBinding();  
  5.        }  
  6.   
  7.        private void SetBinding()  
  8.        {  
  9.            //准备基础Binding  
  10.            Binding bind1 = new Binding(“Text”) { Source=textBox1};  
  11.            Binding bind2 = new Binding(“Text”) { Source = textBox2 };  
  12.            Binding bind3 = new Binding(“Text”) { Source = textBox3 };  
  13.            Binding bind4 = new Binding(“Text”) { Source = textBox4 };  
  14.   
  15.            //准备MultiBinding  
  16.            MultiBinding mb = new MultiBinding() { Mode= BindingMode.OneWay};  
  17.            mb.Bindings.Add(bind1);//注意,MultiBinding对子成分的次第是很机灵的。  
  18.            mb.Bindings.Add(bind2);  
  19.            mb.Bindings.Add(bind3);  
  20.            mb.Bindings.Add(bind4);  
  21.            mb.Converter = new MultiBindingConverter();  
  22.            ///将Binding和MultyBinding关联  
  23.            this.btnSubmit.SetBinding(Button.IsVisibleProperty, mb);  
  24.        }  

注意:

 

 

  • MultiBinding对子成分的逐一十分乖巧,因为这些数目控制了汇总到Convert里多少的各种。
  • MultiBinding的Converter完毕的是IMultiValueConverter。

 

本例的Converter代码如下:

 

[csharp] view
plain
 copy

 

 print?

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Windows.Data;  
  6.   
  7. namespace WpfApplication1.BLL  
  8. {  
  9.     public class MultiBindingConverter:IMultiValueConverter  
  10.     {  
  11.         public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
  12.         {  
  13.             if(!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))&&values[0].ToString()==values[1].ToString()&&values[3].ToString()==values[4].ToString())  
  14.             {  
  15.                 return true;  
  16.             }  
  17.             return false;  
  18.         }  
  19.         /// <summary>  
  20.         /// 该方法不会被调用  
  21.         /// </summary>  
  22.         /// <param name=”value”></param>  
  23.         /// <param name=”targetTypes”></param>  
  24.         /// <param name=”parameter”></param>  
  25.         /// <param name=”culture”></param>  
  26.         /// <returns></returns>  
  27.         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)  
  28.         {  
  29.             throw new NotImplementedException();  
  30.         }  
  31.     }  
  32. }  

程序运转效果如图:

 

图片 75 
  图片 76

小结:

WPF的宗旨情念是变古板的UI驱动数据变成数据驱动UI,支撑那么些视角的基本功正是本章讲的Data
Binding和与之相关的数据校验和数目转换。在行使Binding的时候,最根本的正是安装它的源和路线。

 

 

Data Binding到此讲解甘休。

相关文章