但算法在3层中的分布是不均匀的,算法一般分布在这几处

原文:http://blog.csdn.net/fwj380891124/article/details/8107646

1,Data Binding在WPF中的地位

1,Data Binding在WPF中的地位

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

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

A。数据库内部。

A。数据库内部。

B。读取和写回数据。

B。读取和写回数据。

C。业务逻辑。

C。业务逻辑。

D。数据彰显。

D。数据体现。

E。界面与逻辑的互动。

E。界面与逻辑的互相。

A,B两片段的算法一般都十一分安静,不会随便去改变,复用性也很高;C处与客户需求最严密,最复杂,变化最大,大多少算法都汇聚在此地。D,E负责UI和逻辑的彼此,也占有一定量的算法。

A,B两片段的算法一般都至极平静,不会随便去改变,复用性也很高;C处与客户要求最紧凑,最复杂,变化最大,大多少算法都汇集在此地。D,E负责UI和逻辑的交互,也占据一定量的算法。

驾驭,C部分是先后的主导,是付出的机要,所以我们应当把精力集中在C部分。不过,D,E两局地却时时成为麻烦的来源于。首先那两部分都与逻辑严密有关,一不小心就有大概把自然该放在逻辑层里面的算法写进这两局部(所以才有了MVC、MVP等形式来避免那种气象出现)。其次,那两部分以音讯照旧事件的艺术与逻辑层交流,一旦出现同壹个数额需求在多出彰显/修改时,用于共同的代码错综复杂;最终,D和E本来是互逆的一对儿。但却必要分开来写—–突显数据写1个算法,修改数据再写一个算法。总而言之导致的结果就是D和E两片段会占去一部分算法,搞糟糕还会牵涉不少精力。

显著,C部分是先后的宗旨,是支付的关键,所以大家应有把精力集中在C部分。可是,D,E两有个别却时常成为麻烦的源点。首先那两有的都与逻辑严密相关,一不小心就有大概把本来该放在逻辑层里面的算法写进那两部分(所以才有了MVC、MVP等情势来幸免那种情景出现)。其次,那两局地以音信如故事件的方法与逻辑层交换,一旦出现同五个数额需求在多出显示/修改时,用于共同的代码错综复杂;最终,D和E本来是互逆的一对儿。但却须要分开来写—–显示数据写2个算法,修改数据再写三个算法。不问可知导致的结果就是D和E两部分会占去一部分算法,搞不佳还会拉扯不少生气。

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

难题的来源于在于逻辑层和显示层的身份不稳定——当完结客户须要的时候,逻辑层的确处于大旨地位。但到了完毕UI的时候,浮现层又地处宗旨的身价。WPF作为一种标准的显示层技术,华丽的外观和卡通只是它的外面现象,最关键的是她在深层次上把程序员的想想定势在了逻辑层,让显示层永远处于逻辑层的专属地位。WPF具有这种力量的关键在于它引入了Data
Binding概念及与之配套的Dependency Property系统和DataTemplate。

从观念的Winform转移到WPF上,对于一个三层程序而言,数据存储层由数据库和文件系统组成,数据传输和拍卖依旧使用.NetFramework的ADO.NET等基本类(与Winform开发一样)。体现层则动用WPF类库来贯彻,而浮现层和逻辑层的联络就接纳Data
Binding来促成。可知,Data
Binding在WPF中所起的效益就是高速公路的意义。有了那条高速公路,加工好的数码自动送达用户界面并加以呈现,被用户修改过的多少也会活动传回业务逻辑层,一旦数据被加工好又会被送往界面。。。。程序的逻辑层如同七个强大的引擎一直在运营,用加工好的数目驱动用户界面也文字、图形、动画等花样把多少显示出来——那就是数量驱动UI。

从传统的Winform转移到WPF上,对于三个三层程序而言,数据存储层由数据库和文件系统组成,数据传输和处理仍旧使用.NetFramework的ADO.NET等基本类(与Winform开发一样)。体现层则接纳WPF类库来贯彻,而显示层和逻辑层的联系就动用Data
Binding来落到实处。可见,Data
Binding在WPF中所起的功用就是高速公路的功能。有了那条高速公路,加工好的数额自动送达用户界面并加以突显,被用户修改过的多寡也会活动传回业务逻辑层,一旦数据被加工好又会被送往界面。。。。程序的逻辑层似乎一个强硬的发动机一直在运营,用加工好的数码驱动用户界面也文字、图形、动画等花样把数量体现出来——那就是数据驱动UI。

引入Data
Binding之后,D,E两片段被简化了过多。首先,数据在逻辑层和用户界面直来之去、不涉及逻辑难点,那样的用户界面部分基本上不分包算法:Data
Binding本身就是双向通讯,所以一定于把D和E合二为一;对于五个UI成分关怀同壹个数码的处境,只须求用Data
Binding将这一个UI成分和多少一一关联上(以数据为主干的星形结构),当数码变化后,那几个UI成分会一起显示这一变迁。前边提到的难点也都消除了。更关键的是经过这么的优化,全体与业务逻辑相关的算法都远在工作逻辑层,逻辑层成了三个可以单独运营,完整的种类,而用户界面则不必要任何逻辑代码。完全依赖和从属于工作逻辑层。那样做有八个分明的益处,第叁:即便把UI看做是应用程序的皮,把存储层和逻辑层看作是先后的瓤,我们得以很随意的把皮撕下来换三个新的。第③:因为数据层可以独立运行,自成连串,所以大家可以展开更宏观的单元测试而无需借助UI自动化测试工具—-你完全可以把单元测试看作是3个“看不见的UI”,单元测试只是利用那么些UI绕过真实的UI直接测试工作逻辑罢了。

引入Data
Binding之后,D,E两片段被简化了很多。首先,数据在逻辑层和用户界面直来之去、不涉及逻辑难点,那样的用户界面部分基本上不带有算法:Data
Binding自己就是双向通信,所以一定于把D和E如胶似漆;对于多个UI成分关怀同一个多少的意况,只须要用Data
Binding将那一个UI成分和多少一一关联上(以多少为主旨的星形结构),当数码变化后,这么些UI成分会一起呈现这一变动。前边提到的难点也都消除了。更器重的是通过那样的优化,全体与作业逻辑相关的算法都地处工作逻辑层,逻辑层成了3个方可独自运营,完整的系统,而用户界面则不需求任何逻辑代码。完全依靠和从属于工作逻辑层。那样做有七个显明的利益,第2:假设把UI看做是应用程序的皮,把存储层和逻辑层看作是先后的瓤,大家可以很随便的把皮撕下来换一个新的。第②:因为数据层可以单独运营,自成连串,所以大家得以开展更周详的单元测试而无需借助UI自动化测试工具—-你一点一滴可以把单元测试看作是三个“看不见的UI”,单元测试只是利用这几个UI绕过真正的UI间接测试工作逻辑罢了。

2 ,  Binding 基础

2 ,  Binding 基础

假诺把Binding比作数据的大桥,那么它的双面分别是源(Source)和目标(Target)。数据丛何地来哪儿就是源,到什么地方去何地就是目的。一般景观下,Binding的源是工作逻辑层的对象,Binding的对象是UI层的控件对象。这样数据就会接连不断的通过Binding送达UI界面,被UI层突显,那就成功了多少驱动UI的历程。有了那座桥梁,我们不仅可以操纵车子在源与对象之间是双向通行或然单向通行。还是可以控制数据的放行时机,甚至足以在桥上搭建一些关卡用来更换数据类型或许检验数据的没错。

一旦把Binding比作数据的大桥,那么它的两岸分别是源(Source)和目的(Target)。数据丛哪个地方来哪个地方就是源,到哪个地方去何地就是目的。一般意况下,Binding的源是事情逻辑层的靶子,Binding的对象是UI层的控件对象。那样数据就会接踵而至 蜂拥而至的通过Binding送达UI界面,被UI层突显,那就到位了数据驱动UI的进度。有了那座桥梁,大家不仅可以控制车子在源与对象之内是双向通行恐怕单向通行。还足以控制数据的放行时机,甚至可以在桥上搭建一些关卡用来更换数据类型或许检验数据的不易。

透过对Binding有了三个基本概念之后,让我们看多少个最主题的例证。这几个事例是创建1个粗略的数据源并透过Binding把它连接到UI成分上。

因而对Binding有了三个基本概念之后,让大家看2个最宗旨的例子。那个事例是开创多个回顾的数据源并经过Binding把它连接到UI元素上。

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

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

 

 

[csharp] view
plain
copyprint?

  1. publicclass Student 
  2.     { 
  3.         privatestring name; 
  4.  
  5.         publicstring Name 
  6.         { 
  7.             get { return name; } 
  8.             set 
  9.             { 
  10.                 name = value; 
  11.         } 
  12.     } 

    public class Student

    {
        private string name;
    
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
        }
    }
    

 

以此类很粗略,简单到唯有3个string类型的Name属性。前边说过数据源是三个对象,3个目的自小编可能会有那个数量,那几个数量又通过品质暴光给外界。那么内部哪个成分是你想透过Binding送达UI成分的呢,换句话说,UI成分关注的是哪位属性值的转移呢?那些属性值称之为Binding的不二法门(Path)。但光有品质还万分——-Binding是一种电动机制,当值变化后属性要有能力公告Binding,让Binding把变化传递给UI成分。怎么样才能让叁天品质具备那种文告Binding值已经改变的能力呢?方法是在质量的Set语句中点燃2个PropertyChanged事件。这几个事件不必要大家协调申明,大家要做的事是让作为数据源的类完成System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会活动侦听来自那些接口PropertyChanged事件。

  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.     }  

 

本条类很不难,不难到唯有多个string类型的Name属性。前边说过数据源是1个对象,贰个对象自小编只怕会有为数不少数额,那些多少又通过品质揭发给外界。那么内部哪个成分是您想经过Binding送达UI元素的啊,换句话说,UI成分关注的是哪些属性值的变通吗?这几个属性值称之为Binding的门径(Path)。但光有品质还非凡——-Binding是一种电动机制,当值变化后属性要有能力通告Binding,让Binding把转变传递给UI成分。怎么着才能让3个属性具备那种布告Binding值已经转移的力量吗?方法是在性能的Set语句中激发三个PropertyChanged事件。这些事件不须求我们协调注脚,大家要做的事是让作为数据源的类落成System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源之后,Binding就会自动侦听来自这么些接口PropertyChanged事件。

风平浪静INotifyPropertyChanged接口的类看起来是那般:

 

 

落到实处INotifyPropertyChanged接口的类看起来是如此:

  1. publicclass Student :
    INotifyPropertyChanged 
  2.     { 
  3.         privatestring name; 
  4.  
  5.         publicstring 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.         publicevent PropertyChangedEventHandler
    PropertyChanged; 
  18.     } 

    public class Student : INotifyPropertyChanged

    {
        private string name;
    
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                if (PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

 

透过如此一晋级,当Name属性的值发生变化时PropertyChanged事件就会被激发,Binding接收到那么些事件后意识事件的音信告知它是Name属性值暴发了变通,于是通告Binding目的端的UI成分突显新的值。

[csharp] view
plain
copyprint?

 

 

接下来我们在窗体上准备3个TextBox和Button,代码如下:

  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成分显示新的值。

  1. <Windowx: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.         <TextBoxHeight=”23″HorizontalAlignment=”Left”Margin=”185,43,0,0″Name=”textBox1″VerticalAlignment=”Top”Width=”120″/> 
  7.         <ButtonContent=”Button”Height=”23″HorizontalAlignment=”Left”Margin=”209,96,0,0″Name=”button1″VerticalAlignment=”Top”Width=”75″Click=”button1_Click”/> 
  8.     </Grid> 
  9. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="185,43,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="209,96,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
    

 

后台代码那样写:

下一场我们在窗体上准备三个TextBox和Button,代码如下:

 

 

 

[html] view
plain
copyprint?

  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.        privatevoid button1_Click(object sender, RoutedEventArgs
    e) 
  19.        { 
  20.            stu.Name += “f”; 
  21.            new Window1().Show(); 
  22.        } 
  23.    } 

    ///

    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        Student stu = null;
        public MainWindow()
        {
            InitializeComponent();
            stu = new Student();
            Binding bind = new Binding();
            bind.Source = stu;
            bind.Path = new PropertyPath("Name");
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
    
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            stu.Name += "f";
            new Window1().Show();
        }
    }
    

 

让大家逐句解释一下那段代码,那段代码是MainWIndow的后台代码,它的前端代码就是地点的XAML代码。“Student
stu;”是为MainWindow声多美滋个Student类型的分子变量,那样做的目的是为着在MainWindow的构造器和Button.Click事件处理器中都可以访问到由它引用的Student实例(数据源)。

  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>  

 

后台代码那样写:

在MainWindow的构造器中“InitializeComponent();”是自动生成的代码,用途是开首化UI成分。“stu=new
Student();”那句是创办3个Student实例并用stu成员变量引用它,这几个目的就是我们的数据源。

 

在预备Binding的片段,先利用“Binding bind = new
Binding();”申明Binding类型变量并创办实例,然后使用“bind.Source=stu;”为Binding实例钦赐数据源,最终动用“bind.Path=
new PropertyPath(‘Name’)”语句为Binding钦定访问路径。

 

把数据源和对象连接在共同的任务是利用“BindingOperations.SetBinding(…)”方法成功的,那个方法的3个参数是咱们纪念的主要:

[csharp] view
plain
copyprint?

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

 

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

  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声可瑞康(Ausnutria Hyproca)个Student类型的成员变量,那样做的目标是为着在MainWindow的构造器和Button.Click事件处理器中都可以访问到由它引用的Student实例(数据源)。

运作程序,单击按钮大家将见面到如下的功力图:

 

图片 1

在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指定访问路径。

图片 2

把数据源和目的连接在联名的任务是应用“BindingOperations.SetBinding(…)”方法成功的,那个措施的1个参数是我们记念的第2:

先用这么些做基础,前面大家将讨论Binding的每一个特点。

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

1.3         Binding的源与路径

与数据源的Path原理类似,第四个参数用于为Binding指明为Binding指明把这么些数额送达目的的哪个数据。

Binding
的源相当于多少的源头。Binding对源的须要并不苛刻——只要它是1个目的,并且通过品质(Property)公开自身的数量,它就能同日而语Binding
的源。

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

面前贰个例证已经向大家申明,借使想让作为Binding源的靶子拥有活动布告Binding本人属性值已经已经成形的能力。那么就要求让类落成INotifyChanged接口并在性质的Set语句中激励PropertyChanged事件。在常常生活中,除了采取那种对象作为数据源之外,大家还有越多的选用,比如控件把温馨的容器或子集元素当源、用一个控件做为另三个控件的数据源,把集同盟为ItemControl的数据源、使用XML作为TreeView或Menu的数据源。把七个控件关联到2个“数据制高点”上,甚至干脆不给Binding钦赐数据源、让她协调去找。下边咱们就分述那些处境。

运作程序,单击按钮我们将会看出如下的功效图:

1.3.1       把控件作为Binding源与Binding标记伸张。

图片 3

日前讲过,超过半数动静下Binding的源是逻辑层对象,但局地时候为了让UI爆发联动成效也会使用Binding在控件间创造关系。下边的代码是啊壹个TextBox的Text属性关联到Slider的Value的质量上。

透过地点的事例,大家已经在脑力中创制起来如图所示的模子

 

图片 4

  1. <Windowx: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.         <TextBoxHeight=”23″HorizontalAlignment=”Left”Margin=”141,46,0,0″Name=”textBox1″VerticalAlignment=”Top”Width=”120″Text=”{Binding
    Path=Value,ElementName=slider1}”/> 
  7.         <SliderHeight=”23″HorizontalAlignment=”Left”Margin=”84,106,0,0″Name=”slider1″VerticalAlignment=”Top”Width=”212″/> 
  8.        <ButtonContent=”Button”Height=”23″HorizontalAlignment=”Left”Margin=”166,197,0,0″Name=”button1″VerticalAlignment=”Top”Width=”75″Click=”button1_Click”/> 
  9.     </Grid> 
  10. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="321" Width="401">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="141,46,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Value,ElementName=slider1}"/>
        <Slider Height="23" HorizontalAlignment="Left" Margin="84,106,0,0" Name="slider1" VerticalAlignment="Top" Width="212" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="166,197,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
    

先用那个做基础,前边大家将探究Binding的各个特点。

运作效果如下图:

1.3         Binding的源与路径

 

Binding
的源相当于数量的源流。Binding对源的渴求并不苛刻——只要它是1个目的,并且经过品质(Property)公开本人的数量,它就能作为Binding
的源。

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

前方1个例证已经向我们表明,假若想让作为Binding源的目的拥有活动通告Binding自身属性值已经已经转移的能力。那么就须求让类完成INotifyChanged接口并在性质的Set语句中点燃PropertyChanged事件。在平时生活中,除了行使那种对象作为数据源之外,大家还有越多的精选,比如控件把温馨的器皿或子集成分当源、用1个控件做为另2个控件的数据源,把集合作为ItemControl的数据源、使用XML作为TreeView或Menu的数据源。把四个控件关联到多少个“数据制高点”上,甚至干脆不给Binding指定数据源、让他协调去找。下边大家就分述那一个情况。

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

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

 

面前讲过,大部分情景下Binding的源是逻辑层对象,但局地时候为了让UI爆发联动效用也会使用Binding在控件间成立关联。上边的代码是吧二个TextBox的Text属性关联到Slider的Value的属性上。

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

 

与之等价的C#代码是:

[html] view
plain
copyprint?

 

 

 

  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″}); 

    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标记增添语法:

  1. <TextBoxHeight=”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为…。再想深一步,大家不是不时把函数视为三个值吗?只是以此值在函数执行之后才能取得。同理,我们也得以把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手柄就会跳转至相应的值那里。如下图所示:

 

图片 7

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

为什么一定要在TextBox失去大旨以后才转移值吗?那就引出了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
copyprint?

做为Binding的源大概会有不少性质,通过那几个属性Binding源可以把数量暴光给外界。那么,Binding到底须要关爱哪个属性值呢?就须求用Binding的Path属性来内定了。例如后面那么些例子,大家把Slider控件对象作为数据源,把它的Value属性作为路径。

 

即使在XAML代码中要么Binding类的构造器参数列表中大家应用字符串来代表Path,但Path的实际上类型是PropertyPath。下边让大家来探望哪些创制Path来敷衍真实情况(小编将使用C#和XAML两种代码举行描述)。

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

最简便易行的法门就是一向把Binding关联到Binding源的性能上,后面的事例就是如此,语法如下:

注意:

 

 

  1. <TextBoxHeight=”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,为啥要赋3个Binding类型的值吗?其实大家并不是为Text属性赋值,为了破除那种误解,大家可以把代码读作:为Text属性设置Binding为…。再想深一步,大家不是时常把函数视为一个值吗?只是那些值在函数执行之后才能博取。同理,大家也可以把Binding视为一种直接的、不稳定的赋值情势—–Binding增加很方便的抒发了这一个赋值格局。

 

1.3.2        控制Binding的趋向及数据更新

 

Binding在源与目标以内架起了联络的大桥,暗许情形下多少即可以经过Binding送达目的,也可以透过目的回到源(收集用户对数码的修改)。有时候数据只必要显示给用户,不须要用户修改,这时候可以把Binding格局设置为从目的向源的单向关系以及只在Binding关系确立刻读取三次数据,这亟需大家依照实际情状选取。

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

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

控制Binding数据流向的特性是Model,它的项目是BindingModel的枚举。BindingModel可以取值为TwoWay、OneWay、OneTime、OneWayToSource和Default。那里的Default指的是Binding的形式会依照目标是真实情况来规定,不如是足以编制的(TextBox的Text属性),Default就接纳双向格局。如若是TextBlock,不可编辑,就应用单向格局。

Binding还扶助多元路径(通俗的讲就是联合“点”下去),比如,我们想让二个TextBox显示此外贰个TextBox内容的尺寸,大家得以如此写:

接上一节的小例子,拖动Slider手柄时,TextBox就会突显Slider的此时此刻值(实际上这一块提到到一个Double到String类型的转换,临时忽略不计);如若大家在TextBox里面输入3个适中的值按Tab键、让关节离开TextBox,则Slider手柄就会跳转至相应的值那里。如下图所示:

 

图片 8

 

为啥一定要在TextBox失去大旨以往才转移值吗?那就引出了Binding的其它1特性质—–UpdateSourceTrigger,它的花色是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFous、Explicit和Default。显明,对于Text的Default行为与LostFocus一致,大家只必要把这一个值改成PropertyChanged,则Slider就会随着输入值的转移而转变了。

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

        <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"/>
    

注意:

等效的C#代码是:

附带提一句,Binding还有所NotifyOnSourceUpdated属性和NotifyOnTargetUpdated八个bool类型是性质。如若设置为True,则在源或目的被更新之后就会接触相应的SourceUpdated事件和TargetUpdated事件。实际工作中大家得以监听那五个事件来找出来如何数据或控件被更新了。

 

1.3.3   Binding的路径(Path)

 

做为Binding的源恐怕会有众多品质,通过这一个属性Binding源可以把数量揭穿给外界。那么,Binding到底须求关切哪个属性值呢?就要求用Binding的Path属性来内定了。例如前面这几个例子,大家把Slider控件对象作为数据源,把它的Value属性作为路径。

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

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

尽管在XAML代码中照旧Binding类的构造器参数列表中我们使用字符串来表示帕特h,但Path的实在类型是PropertyPath。下边让大家来看看哪些成立Path来应付实际意况(作者将使用C#和XAML二种代码举办描述)。

运营效果如下图:

最简便的点子就是平素把Binding关联到Binding源的性情上,前面的例证就是这么,语法如下:

 

 

图片 9 大家领略,集合类型是索引器(Indexer)又称之为带参属性。既然是性质,索引器也能作为Path来行使。比如大家想让二个Text博克斯显示此外贰个TextBox的第六个字符,大家得以如此写:

[html] view
plain
copyprint?

 

 

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

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

C#代码如下:

等效的C#代码就是:

 

 

 

 

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

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

[csharp] view
plain
copyprint?

我们竟然足以把Text与[3]期间的点去掉,一样能够正确工作,运营效果如下图:

 

 

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

图片 10 当使用一个集合大概DataView做为数据源时,借使大家想把它暗中同意的因素做为数据源使用,则需求利用下边的语法:

Binding还援救多元路径(通俗的讲就是共同“点”下去),比如,大家想让壹个TextBox显示其余1个TextBox内容的长度,我们得以这么写:

 

 

  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 }); 

    List infos = new List() { “Jim”,”Darren”,”Jacky”};

            textBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source=infos});
            textBox2.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = infos, Mode= BindingMode.OneWay });
            textBox3.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = infos, Mode= BindingMode.OneWay });
    

 

体现效果如下:

[html] view
plain
copyprint?

 

 

图片 11

  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″/>  

假如集合中依旧是汇聚,大家想把子集集合中的成分做帕特h,大家得以使用多级斜线的语法(即“一路”斜线下去),例如:

等效的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=newList<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.    } 

    ///

    /// Window4.xaml 的交互逻辑
    /// </summary>
    public partial class Window4 : Window
    {
        public Window4()
        {
            InitializeComponent();
            List<Contry> infos = new List<Contry>() { new Contry() { Name = "中国", Provinces= new List<Province>(){ new Province(){ Name="四川",Citys=new List<City>(){new  City(){Name="绵阳市"
            }}}}}};
            this.textBox1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source=infos});
            this.textBox2.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Name") { Source = infos });
            this.textBox3.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Citys/Name") { Source = infos });
        }
    }
    
     class City
    {
        public string Name { set; get; }
    }
    
    class Province
    {
        public string Name { set; get; }
        public List<City> Citys { set; get; }
    }
    
    class Contry
    {
        public string Name { set; get; }
        public List<Province> Provinces { get; set; }
    }
    

 

运营效果如图:

[csharp] view
plain
copyprint?

 

 

图片 12

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

1.3.4       “没有Path”的Binding

运行效果如下图:

有的时候大家会在代码中我们看大Path是3个“.”或然索性没有Path的Binding,着实令人摸不着头脑。原来这是一种相比较相当的境况—Binding源本人就是一种多少且不要求Path来指明。典型的string,int等骨干类型都以那般,他们是实例本人就是数额,大家无法钦命通过卓殊属性来做客这一个数据,这是我们只需求将这么些数量设置为.就足以了。在XAML中这些.可以忽略不写,但是在C#中编程必须求带上。上边请看上边那段代码:

 

 

图片 13
咱俩通晓,集合类型是索引器(Indexer)又称为带参属性。既然是性质,索引器也能看做Path来行使。比如我们想让二个TextBox显示别的一个TextBox的第6个字符,我们得以那样写:

  1. <Windowx: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.     <StackPanelHeight=”184″Name=”stackPanel1″Width=”288″> 
  7.         <StackPanel.Resources> 
  8.             <String:Stringx:Key=”myString”> 
  9.                 菩提本无树,何处染纤尘。 
  10.             </String:String> 
  11.              
  12.         </StackPanel.Resources> 
  13.         <TextBlockHeight=”23″Name=”textBlock1″Text=”{Binding
    Path=.,Source={StaticResource ResourceKey=myString}}”/> 
  14.     </StackPanel> 
  15. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:String="clr-namespace:System;assembly=mscorlib"
        Title="Window5" Height="331" Width="538">
    <StackPanel Height="184" Name="stackPanel1" Width="288">
        <StackPanel.Resources>
            <String:String x:Key="myString">
                菩提本无树,何处染尘埃。
            </String:String>
    
        </StackPanel.Resources>
        <TextBlock Height="23" Name="textBlock1" Text="{Binding Path=.,Source={StaticResource ResourceKey=myString}}" />
    </StackPanel>
    

 

上面的代码可以简写成:

[html] view
plain
copyprint?

 

 

 

  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″/>  
  1. <TextBlockHeight=”23″Name=”textBlock1″Text=”{Binding
    .,Source={StaticResource ResourceKey=myString}}”/> 

C#代码如下:

抑或直接写成:

 

 

 

 

[csharp] view
plain
copyprint?

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

 

 

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

注意:

我们竟然足以把Text与[3]时期的点去掉,一样可以正确工作,运营效果如下图:

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

 

 

图片 14
当使用多少个聚众可能DataView做为数据源时,借使我们想把它暗中认可的要素做为数据源使用,则需求使用上面的语法:

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

    string myString = “菩提本无树,明镜亦无台。本来无一物,何处染纤尘。”;

            this.textBlock1.SetBinding(TextBlock.TextProperty, new Binding(".") { Source=myString});
    

 

注意:

[csharp] view
plain
copyprint?

 

 

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

  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.3.5      把Binding指定为源(Source)的两种格局

显示效果如下:

上一节我们上学了什么通过Binding的path属性如何在3个目的上搜索数据。这一节大家将学习如何为Binding指定源(Source)。

 

Binding的源是数量的来自,所以,只要3个对象涵盖数据同时可以通过质量将数据暴光出来,它就能当作Binding的源来使用。包括数据的靶子比比皆是,但必须为Binding的Source钦点合适的对象Binding才能健康办事,常用的措施有:

图片 15

 

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

  • 把常备的CL汉兰达单个对象指定为Source:蕴涵.NetFrameWork自带类型的目标和用户自定义类型的靶子。假使类型完成了INotifyPropertyChanged接口,那可以由此在质量的Set语句里激发PropertyChanged事件来文告Binding已经更新。
  • 把寻常的CL索罗德对象集合内定为Source:包含数组,List<T>,ObservableCollection<T>等联谊类型。实际工作中,大家平时索要将一个聚众类型作为ItemControl的派生类的数目来利用,一般把控件ItemSource属性使用Binding关联到多个凑合对象上。
  • 把ADO.NET数据内定为Source:包含DataTable和DataView对象。
  • 动用XmlDataProvider把XML数据钦命为Source:XML做为标准的数目传输和存储格式,差不多无处不在,我们可以用它象征单个对象或然聚众对象;一些WPF控件是级联的(如Treeview和Menu),大家得以把树状结构的XML数据作为源钦命给与之提到的Binding。
  • 把着重对象(Dependency
    Object)钦点为Source:吝惜对象不仅可以做为Binding
    的靶子,还可以同日而语Binding
    的源。那样就有恐怕形成Binding链。爱抚对象中的器重属品质够做为Binding的帕特h。
  • 把容器的DataContext内定为Source(WPF
    中Binding的暗中认同行为):有时候我们会碰着那样一种景况—-大家赫赫有名知晓将从十二分属性获取数据,但实际运用哪个目的作为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
copyprint?

下边大家利用实例来分别讲述每一种景况:

 

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

  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.    }  

面前的例子都以把单个的CL卡宴对象作为Binding
的源,方法有二种:把目标赋值给Binding.Source属性或然把目的的Name赋值给Binding.ElementName。DataContext被定义在FrameWorkElement类中,这几个类是WPF控件的基类,那象征全体的WPF控件包含布局控件都含有这么些本性。如前所述,WPF的UI布局是树形结构,那个树的各类节点都是控件,因而大家推出1个结论—-在UI树的种种节点都有DataContext属性。那一点很是主要,因为当一个Binding只略知一二本人的帕特h而不通晓自身的源的时候,它会顺着树的同台向树的根部找过去,每经过二个节点都要翻开那几个节点的DataContext属性是不是有所Path所内定的质量。若是有,就把那么些目的作为协调的Source;尽管没有,就一连找下去;如果到树的根部还从未找到,那这一个Binding就从未Source,由此也不会赢得数码,让我们看看上边的事例:

运作效果如图:

先成立贰个名为Student的类,它兼具ID,Name,Age三个属性:

 

 

图片 16

  1. publicclass Student 
  2.     { 
  3.         publicint Id
    { get; set;
  4.         publicstring Name { get; set; } 
  5.         publicint Age
    { get; set;
  6.     } 

    public class Student

    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
    

1.3.4       “没有Path”的Binding

在后在XAML中建立UI界面:

有些时候我们会在代码中我们看大Path是3个“.”大概索性没有Path的Binding,着实令人摸不着头脑。原来这是一种比较奇特的景色—Binding源本人就是一种多少且不须求Path来指明。典型的string,int等主导项目都以这么,他们是实例本人就是数量,大家无能为力内定通过丰富属性来拜访这些数量,那是大家只需求将以此数目设置为.就足以了。在XAML中那个.可以忽略不写,可是在C#中编程必必要带上。上边请看上面那段代码:

 

 

 

[html] view
plain
copyprint?

  1. <Windowx: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.     <StackPanelBackground=”AliceBlue”> 
  7.         <StackPanel.DataContext> 
  8.             <Stu:StudentId=”1″Name=”Darren”Age=”10″></Stu:Student> 
  9.         </StackPanel.DataContext> 
  10.         <Grid> 
  11.             <StackPanelHeight=”283″HorizontalAlignment=”Left”Margin=”12,12,0,0″Name=”stackPanel1″VerticalAlignment=”Top”Width=”418″> 
  12.                 <TextBoxHeight=”23″Name=”textBox1″Width=”120″Margin=”15″Text=”{Binding
    Path=Id}”/> 
  13.                 <TextBoxHeight=”23″Name=”textBox2″Width=”120″Margin=”15″Text=”{Binding
    Path=Name}”/> 
  14.                 <TextBoxHeight=”23″Name=”textBox3″Width=”120″Margin=”15″Text=”{Binding
    Path=Age}”/> 
  15.             </StackPanel> 
  16.         </Grid> 
  17.     </StackPanel> 
  18.      
  19. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Stu="clr-namespace:WpfApplication1"
        Title="Window6" Height="345" Width="464">
    <StackPanel Background="AliceBlue">
        <StackPanel.DataContext>
            <Stu:Student Id="1" Name="Darren" Age="10"></Stu:Student>
        </StackPanel.DataContext>
        <Grid>
            <StackPanel Height="283" HorizontalAlignment="Left" Margin="12,12,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="418">
                <TextBox Height="23" Name="textBox1" Width="120" Margin="15" Text="{Binding Path=Id}"/>
                <TextBox Height="23" Name="textBox2" Width="120" Margin="15" Text="{Binding Path=Name}"/>
                <TextBox Height="23" Name="textBox3" Width="120" Margin="15" Text="{Binding Path=Age}"/>
            </StackPanel>
        </Grid>
    </StackPanel>
    

 

本条UI可以用如下的柱状图来表示:

  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>  

 

上边的代码可以简写成:

图片 17

 

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

 

 

[html] view
plain
copyprint?

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

            <Stu:Student Id="1" Name="Darren" Age="10"></Stu:Student>
        </StackPanel.DataContext>
    

 

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

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

 

抑或直接写成:

 

 

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

                <TextBox Height="23" Name="textBox2" Width="120" Margin="15" Text="{Binding Name}"/>
                <TextBox Height="23" Name="textBox3" Width="120" Margin="15" Text="{Binding Age}"/>
    

 

那样一个TextBox就会沿着树向上找寻可用的DataContext对象。运行效果如下图:

[html] view
plain
copyprint?

 

 

图片 18

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

面前在上学Binding路径的时候,当Binding的Source本身就是数码、不要求运用质量来揭发数据时,Binding的Path可以设置为”.”,亦可省略不写。未来Source也能够简简单单不写了,那样,当有些DataContext为简易类型对象的时候,大家一齐可能看到多个既没有Path,又从未Source的Binding:

 

 

注意:

  1. <Windowx: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.             <TextBlockHeight=”23″HorizontalAlignment=”Left”Margin=”15″Name=”textBlock1″Text=”{Binding}”VerticalAlignment=”Top”/> 
  12.             <TextBlockHeight=”23″HorizontalAlignment=”Left”Margin=”15″Name=”textBlock2″Text=”{Binding}”VerticalAlignment=”Top”/> 
  13.             <TextBlockHeight=”23″HorizontalAlignment=”Left”Margin=”15″Name=”textBlock3″Text=”{Binding}”VerticalAlignment=”Top”/> 
  14.         </StackPanel> 
  15.          
  16.     </Grid> 
  17. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Str="clr-namespace:System;assembly=mscorlib"
        Title="Window7" Height="300" Width="300">
    <Grid>
        <Grid.DataContext>
            <Str:String>Hello DataContext</Str:String>
        </Grid.DataContext>
        <StackPanel>
            <TextBlock Height="23" HorizontalAlignment="Left" Margin="15" Name="textBlock1" Text="{Binding}" VerticalAlignment="Top" />
            <TextBlock Height="23" HorizontalAlignment="Left" Margin="15" Name="textBlock2" Text="{Binding}" VerticalAlignment="Top" />
            <TextBlock Height="23" HorizontalAlignment="Left" Margin="15" Name="textBlock3" Text="{Binding}" VerticalAlignment="Top" />
        </StackPanel>
    
    </Grid>
    

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

运维效果如下图:

 

 

[csharp] view
plain
copyprint?

图片 19

 

你只怕回看,Binding怎么会自行向UI成分上一层查找DataContext并把它当做友好的Source呢?其实,“Binding沿着UI元素树向上找”只是WPF给我们的1个错觉,Binding并没有那么智能。之所以会这么是因为DataContext是1个“依赖属性”,前边的章节大家会详细描述,依赖属性有2个很显明的特色就是您从未为有个别控件的依赖属性赋值的时候,控件会把团结容器的属性值接过来当作自个儿的属性值。实际上属性值是沿着UI元素树向下传递的。

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

在实质上工作中,DataContext属性值的利用格外的灵敏。比如:

注意:

当UI上的多少个控件都接纳Binding关怀同二个目的变化的时候,不妨选拔DataContext。

 

当作为Source的目标无法被直接访问的时候—-比如B窗体内的控件想把A窗体里的控件当作本身的Binding源时,但是A窗体内的控件可访问级别是private类型,那是就足以把这一个控件恐怕控件值作为窗体A的DataContext(那一个天性是Public级其他)那样就足以暴露数据了。

最终顺便带一句,PropertyPath除了用于Binding的Path属性之外,在动画编程的时候也会派上用场(Storyboard.TargetProperty)。在用于动画编程的时候,PropertyPath还有其它一种语法,到时候大家细说。

形象的说,那时候外层的多少就一定于3个多少的“至高点”,只要把成分放上去,旁人就可见看见。此外DataContext自己就是三个依靠属性,我们得以应用Binding把它事关到一个数码源上。

1.3.5      把Binding钦点为源(Source)的二种形式

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

上一节大家学习了怎么通过Binding的path属性怎么着在3个对象上寻找数据。这一节大家将学习怎么为Binding指定源(Source)。

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

Binding的源是数码的源点,所以,只要二个目的涵盖数据同时可以通过质量将数据揭露出来,它就能当作Binding的源来使用。包罗数据的靶子俯拾地芥,但不可以不为Binding的Source钦命合适的对象Binding才能不荒谬办事,常用的方法有:

WPF中的列表式控件都派生自ItemControl类,自然也持续了ItemSource那特本性。ItemSource能够收到两个IEnumerable接口派生类的实例作为协调的值(全部可被迭代遍历的汇集都落到实处了那么些接口,包蕴数组、List<T>等)。各个ItemControl都兼备友好的条款容器Item
Container,例如,ListBox的条目容器是List博克斯Item、Combox的条目容器是ComboxItem。ItemSource里面保存的是一条一条的数据,想要把数据展现出来就要为数量穿上外衣,条目容器就起到了数码外衣的效应。那样将数据外衣和它所对应的条文容器关联起来吧?当然时依靠Binding!只要大家为三个ItemControl设置了ItemSource属性值,ItemControl会自动迭代其中的数量元素,为各种数据成分准备二个条目容器,并应用Binding元素在条款容器和数据成分之间建立起涉嫌,让我们来看3个例子:

 

UI代码如下:

  • 把普通的CL帕杰罗单个对象钦赐为Source:包涵.NetFrameWork自带类型的靶子和用户自定义类型的对象。尽管类型达成了INotifyPropertyChanged接口,那可以通过在性质的Set语句里激发PropertyChanged事件来文告Binding已经更新。
  • 把常备的CL牧马人对象集合内定为Source:蕴含数组,List<T>,ObservableCollection<T>等联谊类型。实际工作中,大家平常要求将七个成团类型作为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的暗许行为):有时候我们会遭遇那样一种景况—-大家肯定了解将从十三分属性获取数据,但具体行使哪个目的作为Binding的源还不鲜明。那时候大家只必要先创设二个Binding,只给它设置Path而不设置Source,让那几个Binding自身去摸索源,那时候,Binding会自动把控件的DataContext作为当作本人的Source(它会顺着控件树平素向外找,直到找到带有Path指定的目标停止)。
  • 通过ElementName指定Source:在C#代码中可以一贯把目的作为Source赋值给Binding,不过XAML不能访问对象,只好选取Name属性来找到对象。
  • 透过Binding的RelataveSource属性相对的内定Source:当控件须要关爱本人的、自个儿容器的大概本身之中有个别属性值就必要动用那种措施。
  • 把ObjectDataProvider内定为Source:当数据源的多寡不是因此品质,而是通过措施揭示给外界的时候,大家得以应用那种对象来包装数据源再把它们内定为Source。
  • 把施用LINQ检索到的多寡作为数据源。

 

 

  1. <Windowx: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.         <StackPanelHeight=”295″HorizontalAlignment=”Left”Margin=”10,10,0,0″Name=”stackPanel1″VerticalAlignment=”Top”Width=”427″> 
  7.             <TextBlockHeight=”23″Name=”textBlock1″Text=”学员编号:”/> 
  8.             <TextBoxHeight=”23″Name=”txtStudentId”Width=”301″HorizontalAlignment=”Left”/> 
  9.             <TextBlockHeight=”23″Name=”textBlock2″Text=”学员列表:”/> 
  10.             <ListBoxHeight=”208″Name=”lbStudent”Width=”305″HorizontalAlignment=”Left”/> 
  11.         </StackPanel> 
  12.     </Grid> 
  13. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window8" Height="356" Width="471">
    <Grid>
        <StackPanel Height="295" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="427">
            <TextBlock Height="23" Name="textBlock1" Text="学员编号:" />
            <TextBox Height="23" Name="txtStudentId" Width="301" HorizontalAlignment="Left"/>
            <TextBlock Height="23" Name="textBlock2" Text="学员列表:" />
            <ListBox Height="208" Name="lbStudent" Width="305" HorizontalAlignment="Left"/>
        </StackPanel>
    </Grid>
    

上边大家运用实例来分别讲述各种处境:

 

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

窗体运转效果如下图:

面前的事例都以把单个的CL中华V对象作为Binding
的源,方法有三种:把目的赋值给Binding.Source属性大概把对象的Name赋值给Binding.ElementName。DataContext被定义在FrameWorkElement类中,那一个类是WPF控件的基类,那意味着全部的WPF控件包含布局控件都富含这性格情。如前所述,WPF的UI布局是树形结构,这么些树的各样节点都以控件,由此大家推出一个结论—-在UI树的各样节点都有DataContext属性。这点13分关键,因为当2个Binding只知道自身的Path而不知道自身的源的时候,它会顺着树的一块儿向树的根部找过去,每经过3个节点都要查阅那么些节点的DataContext属性是还是不是富有帕特h所钦点的习性。若是有,就把这几个目的作为自身的Source;如果没有,就继续找下去;就算到树的根部还未曾找到,那那么些Binding就从不Source,因此也不会博得数码,让我们看看下边的例子:

图片 20

先创建多个名为Student的类,它具备ID,Name,Age贰脾个性:

大家要已毕的效果就是把List<Student>的聚同盟为ListBox的ItemSource,让ListBox展现学员的Name,并采取Text博克斯突显当前入选学员的Id,为了完毕那个意义,大家须求在窗体的构造函数中加上几行代码:

 

 

[csharp] view
plain
copyprint?

  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}); 

    List infos = new List() {

            new Student(){ Id=1, Age=11, Name="Tom"},
            new Student(){ Id=2, Age=12, Name="Darren"},
            new Student(){ Id=3, Age=13, Name="Jacky"},
            new Student(){ Id=4, Age=14, Name="Andy"}
            };
            this.lbStudent.ItemsSource = infos;
            this.lbStudent.DisplayMemberPath = "Name";
    
            this.txtStudentId.SetBinding(TextBox.TextProperty,new Binding("SelectedItem.Id"){ Source=lbStudent});
    

 

运作结果如下图:

  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界面:

图片 21 你只怕回看,那几个事例中并没有出现刚才我们说的Binding。实际上,
this.lbStudent.DisplayMemberPath =
“Name”;这一点代码披露了几许一望可见。注意到含有Path那个单词了呢?那表明它是1个门路。当DisplayMemberPath
被赋值以往,List博克斯在赢得ItemSource的时候就会成立三个等量的ListBoxItem并以DisplayMemberPath的值为Path创制Binding,Binding的靶子是ListBoxItem的始末插件(实际上是2个TextBox,下边就会看见)。

 

如过在ItemControl类的代码里刨根问底,你会发现Binding的长河是在DisplayMemberTemplateSelector类的SelectTemplate方法里做到的。这么些点子的定义格式如下:

 

 

[html] view
plain
copyprint?

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

    public override DataTemplate SelectTemplate(object item, DependencyObject container)

        {
            //逻辑代码
        }
    

 

此处大家倒不用关怀它的实在内容,注意到它的重返值没有,是贰个DataTemplate类型的值。数据的外衣就是由DataTemplate穿上的!当大家没有为ItemControl显示的内定Template的时候SelectTemplate会私行认同的为大家创制3个最简便易行的DataTemplate—-就似乎给多少穿上了一个简短的衣着一样。至于怎么着是Template以及这些措施的共同体代码将会停放与Template相关的篇章中细心去商量。那里大家只关注SelectTemplate内部创造Binding
的几行主要代码:

  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>  

 

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

 

 

  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); 

    FrameworkElementFactory text = ContentPresenter.CreateTextBlockFactory();

            Binding bind = new Binding();
            bind.Path = new PropertyPath(_displayMemberPath);
            bind.StringFormat = _stringFormat;
            text.SetBinding(TextBlock.TextProperty,bind);
    

**图片 22

注意:

**

 

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

此地对新创设的Binding设定了Path而尚未点名Source,紧接那就把它涉及到了TextBlock上。显然,要想取得Source,那么些Binding必要向树根方向搜索包罗_displayMember帕特h钦赐属性的DataContext。

 

**最终大家再看3个体现为数量设置DataTemplate的事例,先把C#代码中的this.lbStudent.DisplayMemberPath

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

 

  1. <Windowx: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.         <StackPanelHeight=”295″HorizontalAlignment=”Left”Margin=”10,10,0,0″Name=”stackPanel1″VerticalAlignment=”Top”Width=”427″> 
  7.             <TextBlockHeight=”23″Name=”textBlock1″Text=”学员编号:”/> 
  8.             <TextBoxHeight=”23″Name=”txtStudentId”Width=”301″HorizontalAlignment=”Left”/> 
  9.             <TextBlockHeight=”23″Name=”textBlock2″Text=”学员列表:”/> 
  10.             <ListBoxHeight=”208″Name=”lbStudent”Width=”305″HorizontalAlignment=”Left”> 
  11.                 <ListBox.ItemTemplate> 
  12.                     <DataTemplate> 
  13.                         <StackPanelName=”stackPanel2″Orientation=”Horizontal”> 
  14.                             <TextBlock  Text=”{Binding Id}”Margin=”5″Background=”Beige”/> 
  15.                             <TextBlockText=”{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> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window8" Height="356" Width="471">
    <Grid>
        <StackPanel Height="295" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="427">
            <TextBlock Height="23" Name="textBlock1" Text="学员编号:" />
            <TextBox Height="23" Name="txtStudentId" Width="301" HorizontalAlignment="Left"/>
            <TextBlock Height="23" Name="textBlock2" Text="学员列表:" />
            <ListBox Height="208" Name="lbStudent" Width="305" HorizontalAlignment="Left">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Name="stackPanel2" Orientation="Horizontal">
                            <TextBlock  Text="{Binding Id}" Margin="5" Background="Beige"/>
                            <TextBlock Text="{Binding Name}" Margin="5"/>
                            <TextBlock  Text="{Binding Age}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    
        </StackPanel>
    </Grid>
    

运营效果图:

 

图片 23

最后特别指示大家一点:

在使用集合类型的数目作为列表控件的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代码如下:

 

  1. <Windowx: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.     <StackPanelHeight=”279″Name=”stackPanel1″Width=”431″> 
  6.         <ListViewHeight=”247″Name=”listView1″Width=”376″> 
  7.             <ListView.View> 
  8.                 <GridView> 
  9.                     
  10.                         <GridViewColumnHeader=”ID”DisplayMemberBinding=”{Binding Id}”Width=”60″> 
  11.                              
  12.                         </GridViewColumn> 
  13.                         <GridViewColumnHeader=”Name”DisplayMemberBinding=”{Binding Name}”Width=”60″> 
  14.  
  15.                         </GridViewColumn> 
  16.                         <GridViewColumnHeader=”Age”DisplayMemberBinding=”{Binding Age}”Width=”60″> 
  17.  
  18.                         </GridViewColumn> 
  19.                         <GridViewColumnHeader=”Sex”DisplayMemberBinding=”{Binding Sex}”Width=”60″> 
  20.  
  21.                         </GridViewColumn> 
  22.                      
  23.                 </GridView> 
  24.             </ListView.View> 
  25.         </ListView> 
  26.     </StackPanel> 
  27. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window9" Height="345" Width="482">
    <StackPanel Height="279" Name="stackPanel1" Width="431">
        <ListView Height="247" Name="listView1" Width="376">
            <ListView.View>
                <GridView>
    
                        <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="60">
    
                        </GridViewColumn>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="60">
    
                        </GridViewColumn>
                        <GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" Width="60">
    
                        </GridViewColumn>
                        <GridViewColumn Header="Sex" DisplayMemberBinding="{Binding Sex}" Width="60">
    
                        </GridViewColumn>
    
                </GridView>
            </ListView.View>
        </ListView>
    </StackPanel>
    

此间大家有几点需求小心的地点:

 

从字面上来精通,ListView和GridView应该属于同一流其余控件,实际上并未如此!ListView是ListBox的派生类而GridView是ViewBase的派生类,ListView中的View是一个ViewBase对象,所以,GridView可以做为ListView的View来使用而不可以看做独立的控件来选用。那里运用理念是结合情势,即ListView有二个View,不过至于是GridView照旧此外门类的View,由程序员本身挑选—-如今唯有3个GridView可用,估计微软在那边还会有扩充。其次,GridView的故事情节属性是Columns,那一个个性是GridViewColumnCollection类型对象。因为XAML支持对故事情节属性的简写,可以简不难单<GridView.Columns>这层标签,间接在GridView的故事情节部分概念二个<GridViewColumn>对象,GridViewColumn中最关键的八个属性是DisplayBinding(类型是BindingBase),使用那么些性子可以钦命这一列使用什么的Binding去关联数据——那与ListBox有点不一样,ListBox使用的是DisplayMemberPath属性(类型是string)。就算想用更扑朔迷离的结构来表示这一标题或数额,则可为GridViewColumn设置HeadTemplate和CellTemplate,它们的品类都以DataTemplate。

运行效果如下:

图片 24

后台代码如下:

 

  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.        } 

    public Window9()

        {
            InitializeComponent();
            DataTable dtInfo = CreateDataTable();
            for (int i = 0; i < 10; i++)
            {
                DataRow dr = dtInfo.NewRow();
                dr[0] = i;
                dr[1] = "猴王" + i;
                dr[2] = i + 10;
                dr[3] = "男";
                dtInfo.Rows.Add(dr);
            }
    
            this.listView1.ItemsSource = dtInfo.DefaultView;
        }
    
        private DataTable CreateDataTable()
        {
            DataTable dt = new DataTable("newtable");

            DataColumn[] columns = new DataColumn[]{new DataColumn("Id"),new DataColumn("Name"),new DataColumn("Age"),new DataColumn("Sex")};
            dt.Columns.AddRange(columns);
            return dt;
        }

经过地方的例证大家早已明白DataTable的DefaultView可以做为ItemSource来使用,拿DataTable直接用行吗,让大家试试看:

 

 

  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; 

    InitializeComponent();

            DataTable dtInfo = CreateDataTable();
            for (int i = 0; i < 10; i++)
            {
                DataRow dr = dtInfo.NewRow();
                dr[0] = i;
                dr[1] = "猴王" + i;
                dr[2] = i + 10;
                dr[3] = "男";
                dtInfo.Rows.Add(dr);
            }
    
            this.listView1.ItemsSource = dtInfo;
    

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

 

荒谬1无法将品种“System.Data.DataTable”隐式转换为“System.Collections.IEnumerable”。存在一个显式转换(是或不是缺少强制转换?)d:\作者的文档\visual
studio
2010\Projects\WpfApplication2\WpfApplication1\Window9.xaml.cs3642WpfApplication1

强烈DataTable不只怕直接拿来为ItemSource赋值。然则,当您把DataTable对象放在1个对象的Context属性的时候,并把2个ItemSource与多个既没有点名Source又尚未点名Path的Binding绑定起来的时候,Binding却能半自动找到它的DefaultView并当作自个儿的Source来使用:

 

  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 dtInfo = CreateDataTable();

            for (int i = 0; i < 10; i++)
            {
                DataRow dr = dtInfo.NewRow();
                dr[0] = i;
                dr[1] = "猴王" + i;
                dr[2] = i + 10;
                dr[3] = "男";
                dtInfo.Rows.Add(dr);
            }
    
            this.listView1.DataContext = dtInfo;
            this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());
    

为此,若是您在代码中发现把DataTable而不是DefaultView作为DataContext值,并且为ItemSource设置1个既无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属性来钦定数量的来自。

咱俩先看2个线性集合的例子。上边的XML文本是一组文本新闻,大家要把它彰显在三个ListView控件里:

 

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



    Andy


    Jacky


    Darren


    DK


    Jim

对应的XAML如下:

 

 

  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> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window10" Height="397" Width="485">
    <StackPanel Width="409" Height="331" Background="LightBlue">
        <ListView Height="302" Name="listView1" Width="396">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID" DisplayMemberBinding="{Binding XPath=@id}" Width="80">
    
                    </GridViewColumn>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding XPath=Name}" Width="150">
    
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </StackPanel>
    

C#代码如下:

 

 

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

程序运转效果如下:

 

图片 25

XMLDataProvider还有三个名为Source的性质,可以直接用它钦赐XML文档所在地点(无论是XML文档是储存在当地硬盘依然互连网地点),所以,后台代码也得以写成如下:

 

  1. privatevoid 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.         } 

    private void BindingInfo()

        {
            //XmlDocument doc = new XmlDocument();
            //doc.Load(@"d:\我的文档\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml");
    
            XmlDataProvider dp = new XmlDataProvider();
            dp.Source = new Uri(@"d:\我的文档\visual studio 2010\Projects\WpfApplication2\WpfApplication1\StudentData.xml");
           // dp.Document = doc;
    
            dp.XPath = @"StudentList/Student";
            this.listView1.DataContext = dp;
            this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());
        }
    

XAML最首要的两句:DisplayMemberBinding=”{Binding
XPath=@id}”和DisplayMemberBinding=”{Binding
XPath=Name}”,他们各自为GridView两列内定了要敬重的XML路径—-很显著,使用@符号加字符串表示的是XML成分的Attribute,不加@符号表示的是子级成分。

 

XML语言能够一本万利的代表树形数据结构,下边的事例是利用TreeView控件来突显全体多少层目录的文件系统,而且,本次把XML数据和XMLDataProvider对象直接写在XAML里面,代码中用到了HierarchicalDataTemplate类,那几个类具有ItemsSource属性,可知由那种Template浮现的数目是足以有子级集合的。代码如下:

 

  1. <Windowx: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.         <XmlDataProviderx:Key=”xdp”XPath=”FileSystem/Folder”> 
  7.             <x:XData> 
  8.                 <FileSystemxmlns=””> 
  9.                     <FolderName=”Books”> 
  10.                         <FolderName=”Programming”> 
  11.                             <FolderName=”Windows”> 
  12.                                 <FolderName=”WPF”> 
  13.                                   
  14.                                 </Folder> 
  15.                                 <FolderName=”Winform”> 
  16.  
  17.                                 </Folder> 
  18.                                 <FolderName=”ASP.NET”> 
  19.  
  20.                                 </Folder> 
  21.                             </Folder> 
  22.                         </Folder> 
  23.                     </Folder> 
  24.                     <FolderName=”Tools”> 
  25.                         <FolderName=”Development”/> 
  26.                         <FolderName=”Designment”/> 
  27.                         <FolderName=”Players”/> 
  28.                     </Folder> 
  29.                 </FileSystem> 
  30.             </x:XData> 
  31.         </XmlDataProvider> 
  32.     </Window.Resources> 
  33.     <Grid> 
  34.         <TreeViewHeight=”283″HorizontalAlignment=”Left”  Name=”treeView1″VerticalAlignment=”Top”Width=”511″ItemsSource=”{Binding Source={StaticResource
    ResourceKey=xdp}}”> 
  35.             <TreeView.ItemTemplate> 
  36.                 <HierarchicalDataTemplateItemsSource=”{Binding XPath=Folder}”> 
  37.                     <TextBlockHeight=”23″HorizontalAlignment=”Left”  Name=”textBlock1″Text=”{Binding
    XPath=@Name}”VerticalAlignment=”Top”/> 
  38.                 </HierarchicalDataTemplate> 
  39.             </TreeView.ItemTemplate> 
  40.         </TreeView> 
  41.          
  42.     </Grid> 
  43. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window11" Height="349" Width="545">
    <Window.Resources>
        <XmlDataProvider x:Key="xdp" XPath="FileSystem/Folder">
            <x:XData>
                <FileSystem xmlns="">
                    <Folder Name="Books">
                        <Folder Name="Programming">
                            <Folder Name="Windows">
                                <Folder Name="WPF">
    
                                </Folder>
                                <Folder Name="Winform">
    
                                </Folder>
                                <Folder Name="ASP.NET">
    
                                </Folder>
                            </Folder>
                        </Folder>
                    </Folder>
                    <Folder Name="Tools">
                        <Folder Name="Development"/>
                        <Folder Name="Designment"/>
                        <Folder Name="Players"/>
                    </Folder>
                </FileSystem>
            </x:XData>
        </XmlDataProvider>
    </Window.Resources>
    <Grid>
        <TreeView Height="283" HorizontalAlignment="Left"  Name="treeView1" VerticalAlignment="Top" Width="511" ItemsSource="{Binding Source={StaticResource ResourceKey=xdp}}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}">
                    <TextBlock Height="23" HorizontalAlignment="Left"  Name="textBlock1" Text="{Binding XPath=@Name}" VerticalAlignment="Top" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    
    </Grid>
    

注意:

 

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

由于本例子设计到了StaticResource和HierarchicalDataTemplate,都以前边的内容,相相比较较难懂,等求学完前边的Resource和Template章节从此再重返便会精晓于胸。

程序运转效果如下图:

图片 26

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

至3.0本子先导,.NET Framework初步辅助LINQ(Language-Intergrated
Query  
语言集成查询),使用LINQ,我们得以一本万利的操作集合对象、DataTable对象和XML对象不必动辄不动把有个别层foreach循环嵌套在一块却只是为着形成贰个很简单的职务。

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

先创制几个名为Student的类:

 

  1. publicclass Student 
  2.   { 
  3.       publicint Id
    { get; set;
  4.       publicstring Name
    { get; set;
  5.       publicint Age
    { get; set;
  6.   } 

    public class Student

    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
    

XAML代码如下:

 

 

  1. <Windowx: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.         <ListViewHeight=”311″HorizontalAlignment=”Left”Margin=”10,10,0,0″Name=”listView1″VerticalAlignment=”Top”Width=”494″> 
  7.             <ListView.View> 
  8.                 <GridView> 
  9.                     <GridViewColumnHeader=”ID”DisplayMemberBinding=”{Binding Id}”Width=”100″/> 
  10.                     <GridViewColumnHeader=”Name”DisplayMemberBinding=”{Binding Name}”Width=”100″/> 
  11.                     <GridViewColumnHeader=”Age”DisplayMemberBinding=”{Binding Age}”Width=”100″/> 
  12.                 </GridView> 
  13.             </ListView.View> 
  14.         </ListView> 
  15.     </Grid> 
  16. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window12" Height="372" Width="538">
    <Grid>
        <ListView Height="311" HorizontalAlignment="Left" Margin="10,10,0,0" Name="listView1" VerticalAlignment="Top" Width="494">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="100"/>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100"/>
                    <GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" Width="100"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
    

 

 

后台代码如下:

  1. privatevoid 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.         } 

    private void BindingData()

        {
            List<Student> infos = new List<Student>()
            {
                new Student(){Id=1, Age=29, Name="Tim"},
                 new Student(){Id=1, Age=28, Name="Tom"},
                  new Student(){Id=1, Age=27, Name="Kyle"},
                   new Student(){Id=1, Age=26, Name="Tony"},
                    new Student(){Id=1, Age=25, Name="Vina"},
                     new Student(){Id=1, Age=24, Name="Mike"}
            };
            this.listView1.ItemsSource = from stu in infos where stu.Name.StartsWith("T") select stu;
        }
    

一旦数量存放在二个DataTable对象里面,则后台代码如下:

 

  1. privatevoid 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.        } 

    private void BindingDataByDataTable()

        {
            DataTable dtInfo = CreateDataTable();
            this.listView1.ItemsSource = from row in dtInfo.Rows.Cast<DataRow>()
                                         where Convert.ToString(row["Name"]).StartsWith("T")
                                         select new Student()
                                         {
                                             Id = Convert.ToInt32(row["Id"]), Name=Convert.ToString(row["Name"]),Age=Convert.ToInt32(row["Age"])
                                         };
    
        }
    

只要数量存储在XML里面,存储格式如下:

 

 

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












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

 

 

  1. privatevoid 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.         } 

    private void BindingDataByXml()

        {
            XDocument xd = XDocument.Load(@"d:\我的文档\visual studio 2010\Projects\WpfApplication2\WpfApplication1\testDate.xml");
    
            this.listView1.ItemsSource = from element in xd.Descendants("Student")
                                         where element.Attribute("Name").Value.StartsWith("T")
                                         select new Student()
                                             {
                                                 Name = element.Attribute("Name").Value,
                                                 Id = Convert.ToInt32(element.Attribute("Id").Value),
                                                 Age = Convert.ToInt32(element.Attribute("Age").Value)
                                             };
        }
    

 

程序运维效果如下图:

图片 27

1.3.11    使用ObjectDataProvider作为binding的Source

了不起状态下,上游程序员将类设计好、使用质量把多少暴光出来,下游程序员将那些类作为Binding的Source、把品质作为Binding的帕特h来消费这个类。但很难保障七个类的本性都用属性暴光出来,比如大家要求的数量或然是格局的重回值。而重复设计底层类的危害和费用会相比高,况且黑盒引用类库的情事下大家不可以改动已经编译好的类,那时候须求拔取ObjectDataProvider来包装做为Binding源的多寡对象了。

ObjcetDataProvider
顾名思义就是把对目的作为数据源提需求Binding。前边还提到过XmlDataProvider,那五个类的父类都以DataSourceProvider抽象类。

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

 

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

咱俩先写2个分外不难的小例子来打听下ObjectDataProvider类。随便新建多个WPF窗体,窗体内拖放三个控件,控件的Click事件如下:

 

 

  1. privatevoid 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.      } 

    private void button1_Click(object sender, RoutedEventArgs e)

        {
            ObjectDataProvider odp = new ObjectDataProvider();
            odp.ObjectInstance = new Caculate();
            odp.MethodName="Add";
            odp.MethodParameters.Add("100");
            odp.MethodParameters.Add("200");
            MessageBox.Show(odp.Data.ToString());
    
        }
    

运作程序,单击button大家会见到如下界面:

 

图片 28

通过那个程序大家得以精通到ObjectDataProvider对象和它被卷入的靶子关联如下图:

图片 29

 

打探了ObjectDataProvider的应用方法,大家看看怎样把它当作Binding的Source来使用。程序的XAML代码和截图如下:

 

  1. <Windowx: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.     <StackPanelBackground=”LightBlue”> 
  6.         <TextBoxHeight=”23″Name=”textBox1″Width=”200″HorizontalAlignment=”Left”Margin=”15″/> 
  7.         <TextBoxHeight=”23″Name=”textBox2″Width=”200″HorizontalAlignment=”Left”Margin=”15″/> 
  8.         <TextBoxHeight=”23″Name=”textBox3″Width=”200″HorizontalAlignment=”Left”Margin=”15″/> 
  9.     </StackPanel> 
  10. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window14" Height="202" Width="345">
    <StackPanel Background="LightBlue">
        <TextBox Height="23" Name="textBox1" Width="200" HorizontalAlignment="Left" Margin="15"/>
        <TextBox Height="23" Name="textBox2" Width="200" HorizontalAlignment="Left" Margin="15"/>
        <TextBox Height="23" Name="textBox3" Width="200" HorizontalAlignment="Left" Margin="15"/>
    </StackPanel>
    

图片 30

 

那几个程序完成的功用是,我在前七个TextBox里面输入值的时候,第十个TextBox会显示前八个文本框里面相加之和。把代码写在二个名为SetBinding的办法里面,然后在窗体的构造器里面调用那几个主意:

 

  1. privatevoid 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.        } 

    private void SetBinding()

        {
            ObjectDataProvider objpro = new ObjectDataProvider();
            objpro.ObjectInstance = new Caculate();
            objpro.MethodName = "Add";
            objpro.MethodParameters.Add("0");
            objpro.MethodParameters.Add("0");
            Binding bindingToArg1 = new Binding("MethodParameters[0]") { Source=objpro,BindsDirectlyToSource=true, UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged};
            Binding bindingToArg2 = new Binding("MethodParameters[1]") { Source=objpro,BindsDirectlyToSource=true,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};
            Binding bindToResult = new Binding(".") { Source=objpro};
            this.textBox1.SetBinding(TextBox.TextProperty, bindingToArg1);
            this.textBox2.SetBinding(TextBox.TextProperty, bindingToArg2);
            this.textBox3.SetBinding(TextBox.TextProperty,bindToResult);
        }
    

让我们先来分析一下方面两段代码,前边说过,ObjectDataProvider类的意义是包装二个以艺术暴露数据的靶子,那里大家先创制了一个ObjectDataProvider的对象,然后用一个Caculate对象为其ObjectInstance对象赋值—那就把三个Caculate对象包装在了ObjectDataProvider里面。还有别的3个方法来创建被卷入的目标,那就是报告包装对象被包裹对象的品类和希望调用的构造器,让ObjectDataProvider本人来创制对象,代码大约是如此:

 

 

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

    //—

            objpro.ObjectInstance = typeof(Caculate);
            objpro.ConstructorParameters.Add(arg1);
            objpro.ConstructorParameters.Add(arg2);
            //----
    

因为在XAML中创立对象比较麻烦,可读性差,所以大家一般会在XAML代码中行使那种指定项目和构造器的章程。

 

继之,大家使用MethodName属性指定要调用的Caculator对象中名为Add的点子—难点又来了,若是Caculator有多少个构造器参数的主意Add应该什么区分?大家知道,重载方法的区分在于参数列表,紧接着两句就是向MethodParameter属性里面参与七个string类型的参数,那就相当于告诉ObjectDataProvider对象去调用Caculator对象中保有八个string类型参数的Add方法,换句话说,MethodParameter对于参数的反响是充裕敏锐的。

准备好数据源之后,大家准备开创Binding。前边大家已经讲过使用索引器作为Binding的帕特h,第3个Binding它的Source是3个ObjectDataProvider对象,Path是ObjectDataProvider中MethodParameters所引用的率先个成分。BindsDirectlyToSource那句话是报告Binding只是将UI上的值传递给源而不是被ObjectDataProvider包装的Caculator,同时UpdateSourceTrigger设置为UI只要一有变动就更新Source。第2个Binding只是对第二个的翻版,只是把Path属性指向了第三个要素。第两个binding仍旧拔取ObjectDataProvider作为Source,但接纳“.”作为帕特h—-前边讲过,当数据源自己就是数额的时候就用“.”来做为Path,在XAML中”.”可以不写。

注意:

在ObjectDataProvider对象作为Binding的Source的时候,这些目标自作者就表示了数码,所以那里的Path使用的“.”,而不是Data属性。

最后几行就是将Binding对象关系到一个TextBox对象上。程序运维效果如下:

图片 31

诚如意况下多少从那里来,哪儿就是Binding的Source,数据到哪个地方去,何地就是Binding
的Target。按那一个理论,前七个TextBox应该是ObjcetDataProvider的源,而ObjcetDataProvider对象又是终极1个Text博克斯的源。但实质上,五个Text博克斯都是ObjcetDataProvider作为数据源,只是前三个在数据流向上做了限定,那样做的因由不外乎有几个:

一 、ObjcetDataProvider的MethodParameter不是倚重属性,不大概当做Binding的靶子。

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

1.3.12    使用Binding的RelativeSource

当2个Binding有明显的源于的时候,大家可以通过Source恐怕ElementName赋值的办法让Binding与之提到。某些时候大家不大概显然作为Source对象叫什么名字,然而大家知晓它与做为Binding目的对象在UI上的相持关系,比如控件本身关系本身的有些数据,关联本人某级容器的数目,那时候就需求用到Binding的RelativeSource属性。

RelativeSource属性的品类是RelativeSource类,通过那些类的多少个静态大概非静态的习性大家得以操纵它寻找相对数据源的方法。请看下边那段代码:

 

  1. <Windowx: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.     <GridBackground=”Red”Margin=”10″x:Name=”gd1″> 
  6.         <DockPanelx:Name=”dp1″Margin=”10″Background=”Orange”> 
  7.             <GridBackground=”Yellow”Margin=”10″x:Name=”gd2″> 
  8.                 <DockPanelName=”dp2″Margin=”10″Background=”LawnGreen”> 
  9.                     <TextBox  Name=”textBox1″  Margin=”10″FontSize=”24″/> 
  10.                 </DockPanel> 
  11.             </Grid> 
  12.         </DockPanel> 
  13.     </Grid> 
  14. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window15" Height="375" Width="516">
    <Grid Background="Red" Margin="10" x:Name="gd1">
        <DockPanel x:Name="dp1" Margin="10" Background="Orange">
            <Grid Background="Yellow" Margin="10" x:Name="gd2">
                <DockPanel Name="dp2" Margin="10" Background="LawnGreen">
                    <TextBox  Name="textBox1"  Margin="10" FontSize="24"/>
                </DockPanel>
            </Grid>
        </DockPanel>
    </Grid>
    

界面运维结果如下:

 

图片 32

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

 

  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); 

    RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);

            rs.AncestorLevel = 1;
            rs.AncestorType = typeof(Grid);
            Binding bind = new Binding("Name") { RelativeSource = rs };
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
    

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

 

 

  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类型对象后把它当做自身的源。运维效果如下图:

 

图片 33 若是把代码改成如下那样:

 

  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); 

    RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);

            rs.AncestorLevel = 2;
            rs.AncestorType = typeof(DockPanel);
            Binding bind = new Binding("Name") { RelativeSource = rs };
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
    

如故把XAML代码改成如下:

 

 

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

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

运转效果如下:

 

图片 34

假如Text博克斯要求关联本人的Name属性,那么代码应该这么写:

 

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

    RelativeSource rs = new RelativeSource(RelativeSourceMode.Self);

            Binding bind = new Binding("Name") { RelativeSource = rs };
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
    

相应的XAML代码如下:

 

 

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

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

运作效果如下图:

 

图片 35

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是三个抽象类,在使用的时候我们须要创制它的派生类并贯彻它的Validate方法的重返值是ValidateionResult类型对象,借使因此认证,就把ValidateionResult对象的IsValidate属性设为true,反之,则须要将IsValidate设置为false并为其ErrorContent属性设置一个确切的音信内容(一般是字符串)。

上边这一个顺序的UI绘制壹个TextBox和三个Slider,然后在后台C#代码中树立Binding把它们关联起来—-
已Slide为源,TextBox为对象。Slider的取值范围是0~100,也等于说大家须要验证TextBox中输入的值是还是不是在0~100之间。

程序的XAML部分如下:

 

  1. <Windowx: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.     <StackPanelBackground=”AliceBlue”Margin=”10″> 
  6.         <TextBoxHeight=”23″Name=”textBox1″Width=”200″Margin=”20″/> 
  7.         <SliderHeight=”23″Name=”slider1″Width=”219″Maximum=”100″/> 
  8.     </StackPanel> 
  9. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window16" Height="300" Width="300">
    <StackPanel Background="AliceBlue" Margin="10">
        <TextBox Height="23" Name="textBox1" Width="200" Margin="20"/>
        <Slider Height="23" Name="slider1" Width="219" Maximum="100" />
    </StackPanel>
    

为了举行校验,大家准备一个ValidationRule的派生类,内容如下:

 

 

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

下一场在窗体里面建立Binding:

 

 

  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.        } 

    public Window16()

        {
            InitializeComponent();
            Binding bind =new Binding("Value") { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};
            ValidationRule rule = new RangeValidationRule();
            rule.ValidatesOnTargetUpdated = true;
            bind.ValidationRules.Add(rule);
    
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
        }
    

达成后运维程序,当输入0~100之间的值的时候程序不奇怪突显,不过输入区间之外的值的时候TextBox会显示为革命边框,表示值是不当的,不可以传值给Source。效果如下图:

 

图片 36图片 37

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

图片 38图片 39

您大概回顾,在验证错误的时候,ValidationResult会教导一条错误音讯,那么怎么着使用这条错误新闻呢?想要用到那或多或少,要求采取后边会详细讲解到的知识—–路由事件(Routed
伊芙nt)。

先是在开立Binding
的时候要把Binding的靶子的NotifyOnValidationError属性设置为true,那样,当数码校验战败的时候Binding就如报警器一样暴发二个信号。这么些信号会在已Binding对象的Target为源点的UI树上举行传播。信号没到达壹个节点,假使这几个节点设置了对那种信号的侦听器(事件处理器),那么这些侦听器就会被触发并处理那些信号,信号处理完成后,仍能是或不是让信号继续沿着UI树向上传播—那就是路由事件。信号在UI树上传递的进度称为路由(Route)。

树立Binding的代码如下:

 

  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.        } 

    public Window16()

        {
            InitializeComponent();
            Binding bind =new Binding("Value") { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};
            ValidationRule rule = new RangeValidationRule();
            rule.ValidatesOnTargetUpdated = true;
            bind.ValidationRules.Add(rule);
            bind.NotifyOnValidationError = true;
            this.textBox1.SetBinding(TextBox.TextProperty, bind);
            this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));
        }
    

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

 

 

  1. privatevoid 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.         } 

    private void ValidationError(object sender, RoutedEventArgs e)

        {
            if (Validation.GetErrors(textBox1).Count > 0)
            {
                this.textBox1.ToolTip = Validation.GetErrors(textBox1)[0].ErrorContent.ToString();
            }
            else
            {
                this.textBox1.ToolTip = "";
            }
        }
    

程序一旦校验失利,就会利用ToolTip指示用户,如下图:

 

图片 40

1.4.2    Binding的数量转换

面前的诸多例证大家都在运用Binding将TextBox和Slider之间建立关系—-Slider控件作为Source(Path的Value属性),Text博克斯作为Target(目的属性为Text)。不了解我们有没有留意到,Slider的Value属性是Double类型值,而Text博克斯的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里面值转换为对应的头像图片UOdysseyI(亦是oneway)。

 

当蒙受那么些情况,我们只可以协调入手写Converter,方法是开创三个类并让这么些类已毕IValueConverter接口,IValueConverter定义如下:

 

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

当数码从Binding的Source流向Target的时候,Convert方法将被调用;反之ConvertBack将被调用。那多少个章程的参数列表一模一样:第3个参数为Object。最大限度的保险了Convert的重中之重。第三个参数用于分明再次回到参数的回到类型。第多个参数为了将卓殊的参数传入方法,若必要传递八个音信,则需求将新闻做为1个聚集传入即可。

 

Binding对象的Mode属性将影响那三个方法的调用;若是Mode为TwoWay或Default行为与TwoWay一致则多少个办法都有大概被调用。若是Mode是OneWay或许Default行为与OneWay一致则唯有Convert方法会被调用。此外景况同理。

上面这几个事例是一个Converter的归咎实例,程序的用途是向玩家展现一些军用飞机的图景新闻。

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

 

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

    public enum Category

    {
        Bomber,
        Fighter
    }
    
    public enum State
    {
        Available,
        Locked,
        Unknown
    }
    
    public class Plane
    {
        public Category category { get; set; }
        public State state { get; set; }
        public string name { get; set; }
    }
    

在UI里,Category的状态被映射为图标,那八个图标已经被小编放入项目中,如图:

 

图片 41

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

 

  1. publicclass CategoryToSourceConverter:IValueConverter 
  2.     { 
  3.  
  4.         publicobject 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.                     returnnull; 
  17.                      
  18.             } 
  19.         } 
  20.  
  21.         publicobject ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo
    culture) 
  22.         { 
  23.             thrownew NotImplementedException(); 
  24.         } 
  25.     } 

    public class CategoryToSourceConverter:IValueConverter

    {
    
        public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)
        {
            Category category = (Category)value;
            switch (category)
            {
                case Category.Bomber:
                    return @"ICONS/Bomber.png";
    
                case Category.Fighter:
                    return @"ICONS/Fighter.png";
    
                default:
                    return null;
    
            }
        }
    
        public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    
  26. publicclass StateToNullableBoolConverter:IValueConverter 

  27.     { 
  28.  
  29.         publicobject Convert(object value,
    Type targetType, object parameters,
    System.Globalization.CultureInfo
    culture) 
  30.         { 
  31.             State state = (State)value; 
  32.             switch (state) 
  33.             { 
  34.                 case State.Available: 
  35.                     returntrue; 
  36.                      
  37.                 case State.Locked: 
  38.                     returnfalse; 
  39.                 case State.Unknown: 
  40.                      
  41.                 default: 
  42.                     returnnull; 
  43.             } 
  44.         } 
  45.  
  46.         publicobject ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo
    culture) 
  47.         { 
  48.             bool? nb = (bool?)value; 
  49.             switch (nb) 
  50.             { 
  51.                 casetrue: 
  52.                     return State.Available; 
  53.                 casefalse: 
  54.                     return State.Locked; 
  55.                 casenull: 
  56.                 default: 
  57.                     return State.Unknown; 
  58.                      
  59.             } 
  60.         } 
  61.     } 

    public class StateToNullableBoolConverter:IValueConverter

    {
    
        public object Convert(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)
        {
            State state = (State)value;
            switch (state)
            {
                case State.Available:
                    return true;
    
                case State.Locked:
                    return false;
                case State.Unknown:
    
                default:
                    return null;
            }
        }
    
        public object ConvertBack(object value, Type targetType, object parameters, System.Globalization.CultureInfo culture)
        {
            bool? nb = (bool?)value;
            switch (nb)
            {
                case true:
                    return State.Available;
                case false:
                    return State.Locked;
                case null:
                default:
                    return State.Unknown;
    
            }
        }
    }
    

下边我们来看看哪些在XAML代码里面来用度这个Converter:

 

 

  1. <Windowx: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:CategoryToSourceConverterx:Key=”cts”/> 
  8.         <local:StateToNullableBoolConverterx:Key=”snb”/> 
  9.     </Window.Resources> 
  10.     <StackPanelName=”stackPanel1″Background=”AliceBlue”Margin=”10″> 
  11.         <ListBox  Name=”listBox1″Height=”160″Margin=”5″> 
  12.             <ListBox.ItemTemplate> 
  13.                 <DataTemplate> 
  14.                     <StackPanelOrientation=”Horizontal”> 
  15.                         <ImageHeight=”16″Name=”image1″Stretch=”Fill”Width=”16″Source=”{Binding
    Path=category,Converter={StaticResource cts}}”/> 
  16.                         <TextBlockHeight=”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.         <ButtonContent=”Load”Height=”23″Name=”button1″Width=”131″Margin=”5″Click=”button1_Click”/> 
  23.         <ButtonContent=”Save”Height=”23″Name=”button2″Width=”131″Margin=”5″Click=”button2_Click”/> 
  24.     </StackPanel> 
  25. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1.BLL"
        Title="Window17" Height="327" Width="460">
    <Window.Resources>
        <local:CategoryToSourceConverter x:Key="cts" />
        <local:StateToNullableBoolConverter x:Key="snb" />
    </Window.Resources>
    <StackPanel Name="stackPanel1" Background="AliceBlue" Margin="10">
        <ListBox  Name="listBox1" Height="160" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Height="16" Name="image1" Stretch="Fill" Width="16" Source="{Binding Path=category,Converter={StaticResource cts}}"/>
                        <TextBlock Height="23" Name="textBlock1" Text="{Binding name}" Margin="8,0" Width="80"/>
                        <CheckBox  Height="16" Name="checkBox1" IsChecked="{Binding Path=state,Converter={StaticResource snb}}" IsThreeState="True"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Content="Load" Height="23" Name="button1" Width="131" Margin="5" Click="button1_Click" />
        <Button Content="Save" Height="23" Name="button2" Width="131" Margin="5" Click="button2_Click" />
    </StackPanel>
    

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

 

 

  1. /// <summary> 
  2.         /// Load按钮事件处理器 
  3.         /// </summary> 
  4.         /// <param
    name=”sender”></param> 
  5.         /// <param
    name=”e”></param> 
  6.         privatevoid 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.         privatevoid 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.         } 

    ///

        /// Load按钮事件处理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            List<Plane> infos = new List<Plane>() { 
            new Plane(){ category= Category.Bomber,name="B-1", state= State.Unknown},
            new Plane(){ category= Category.Bomber,name="B-2", state= State.Unknown},
            new Plane(){ category= Category.Fighter,name="F-22", state= State.Locked},
            new Plane(){ category= Category.Fighter,name="Su-47", state= State.Unknown},
            new Plane(){ category= Category.Bomber,name="B-52", state= State.Available},
            new Plane(){ category= Category.Fighter,name="J-10", state= State.Unknown},
            };
            this.listBox1.ItemsSource = infos;
        }
        /// <summary>
        /// Save按钮事件处理器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (Plane item in listBox1.Items)
            {
                sb.AppendLine(string.Format("Categroy={0},State={1},Name={2}",item.category,item.state,item.name));
            }
            File.WriteAllText(@"D:\PlaneList.text",sb.ToString());
        }
    

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

 

图片 42图片 43

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

图片 44

1.5   MultiBinding(多路Binding)

神蹟UI需求出示的数码来源不止二个多少来自决定,这一个时候就须要接纳MultiBinding,即多路绑定。MultiBinding与Binding一样均以BindingBase为基类,约等于说,凡是能用Binding的场所都能动用MultiBinding。MutiBinding具有一个Bindings的个性,其品种是Connection<BindingBase>,通过那个本性,MultiBinding把一组Binding对象聚合起来,处在那一个Binding结合中的对象足以拥有和谐的数额校验和转换机制。它们汇集起来的多大校壹头决定传往MultiBinding目标的多寡。如下图:

图片 45

考虑这么一个必要,有二个用以新用户注册的UI(四个TextBox和贰个Button),还有如下一些限量:

 

  • 先是,2个TextBox用于输入用户名,须求数据必须一律。
  • 其三,两个TextBox用于显示输入的邮箱,须要数据必须一律。
  • 当TextBox的始末全方位符合需求的时候,Button可用。

 

此UI的XAML代码如下:

 

  1. <Windowx: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.     <StackPanelName=”stackPanel1″  Margin=”10″Background=”AliceBlue”> 
  6.         <TextBoxHeight=”23″Name=”textBox1″Margin=”5″/> 
  7.         <TextBoxHeight=”23″Name=”textBox2″Margin=”5″/> 
  8.         <TextBoxHeight=”23″Name=”textBox3″Margin=”5″/> 
  9.         <TextBoxHeight=”23″Name=”textBox4″Margin=”5″/> 
  10.         <ButtonContent=”Regist”Height=”23″Name=”btnSubmit”Width=”75″  Margin=”10″/> 
  11.     </StackPanel> 
  12. </Window> 

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window18" Height="300" Width="300">
    <StackPanel Name="stackPanel1"  Margin="10" Background="AliceBlue">
        <TextBox Height="23" Name="textBox1" Margin="5" />
        <TextBox Height="23" Name="textBox2" Margin="5" />
        <TextBox Height="23" Name="textBox3" Margin="5" />
        <TextBox Height="23" Name="textBox4" Margin="5" />
        <Button Content="Regist" Height="23" Name="btnSubmit" Width="75"  Margin="10"/>
    </StackPanel>
    

后台代码如下:

 

 

  1. public Window18() 
  2.        { 
  3.            InitializeComponent(); 
  4.            SetBinding(); 
  5.        } 
  6.  
  7.        privatevoid 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.        } 

    public Window18()

        {
            InitializeComponent();
            SetBinding();
        }
    
        private void SetBinding()
        {
            //准备基础Binding
            Binding bind1 = new Binding("Text") { Source=textBox1};
            Binding bind2 = new Binding("Text") { Source = textBox2 };
            Binding bind3 = new Binding("Text") { Source = textBox3 };
            Binding bind4 = new Binding("Text") { Source = textBox4 };
    
            //准备MultiBinding
            MultiBinding mb = new MultiBinding() { Mode= BindingMode.OneWay};
            mb.Bindings.Add(bind1);//注意,MultiBinding对子元素的顺序是很敏感的。
            mb.Bindings.Add(bind2);
            mb.Bindings.Add(bind3);
            mb.Bindings.Add(bind4);
            mb.Converter = new MultiBindingConverter();
            ///将Binding和MultyBinding关联
            this.btnSubmit.SetBinding(Button.IsVisibleProperty, mb);
        }
    

注意:

 

 

  • MultiBinding对子成分的逐条非凡敏锐,因为这些数量控制了集中到Convert里多少的次第。
  • MultiBinding的Converter完毕的是IMultiValueConverter。

 

本例的Converter代码如下:

 

  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.     publicclass MultiBindingConverter:IMultiValueConverter 
  9.     { 
  10.         publicobject Convert(object[]
    values, Type targetType, object parameter,
    System.Globalization.CultureInfo
    culture) 
  11.         { 
  12.             if(!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))&&values[0].ToString()==values[1].ToString()&&values[3].ToString()==values[4].ToString()) 
  13.             { 
  14.                 returntrue; 
  15.             } 
  16.             returnfalse; 
  17.         } 
  18.         /// <summary> 
  19.         /// 该形式不会被调用 
  20.         /// </summary> 
  21.         /// <param
    name=”value”></param> 
  22.         /// <param
    name=”targetTypes”></param> 
  23.         /// <param
    name=”parameter”></param> 
  24.         /// <param
    name=”culture”></param> 
  25.         ///
    <returns></returns> 
  26.         publicobject[]
    ConvertBack(object value, Type[]
    targetTypes, object parameter,
    System.Globalization.CultureInfo
    culture) 
  27.         { 
  28.             thrownew NotImplementedException(); 
  29.         } 
  30.     } 
  31. using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Data;

    namespace WpfApplication1.BLL
    {

    public class MultiBindingConverter:IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if(!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))&&values[0].ToString()==values[1].ToString()&&values[3].ToString()==values[4].ToString())
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 该方法不会被调用
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetTypes"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    }

程序运维效果如图:

 

图片 46    图片 47

小结:

WPF的核情感念是变古板的UI驱动数据变成数据驱动UI,支撑这么些看法的功底就是本章讲的Data
Binding和与之殃及池鱼的多上将验和数目转换。在应用Binding的时候,最要紧的就是安装它的源和路径。

 

 

Data Binding到此讲解停止。

[html] view
plain
copyprint?

 

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

就为外层StackPanel的DataContext举办了赋值—-它是三个Student对象。2个TextBox通过Binding获取值,但只为Binding钦赐了Path,没有点名Source。简写成这么也足以:

 

 

[html] view
plain
copyprint?

 

  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对象。运转效果如下图:

 

图片 48

日前在求学Binding路径的时候,当Binding的Source本身就是数据、不须要接纳性质来揭示数据时,Binding的Path可以设置为”.”,亦可省略不写。以后Source也得以归纳不写了,那样,当某些DataContext为简便类型对象的时候,大家完全或许看到1个既没有帕特h,又不曾Source的Binding:

 

[html] view
plain
copyprint?

 

  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给我们的3个错觉,Binding并不曾那么智能。之所以会如此是因为DataContext是贰个“看重属性”,前边的章节我们会详细描述,看重属性有二个很鲜明的特色就是你从未为某些控件的依靠属性赋值的时候,控件会把自身容器的属性值接过来当作自身的属性值。实际上属性值是沿着UI成分树向下传递的。

在骨子里工作中,DataContext属性值的应用非凡的灵活。比如:

当UI上的两个控件都采取Binding关切同一个对象变化的时候,不妨采用DataContext。

当作为Source的目的不或者被一向访问的时候—-比如B窗体内的控件想把A窗体里的控件当作本人的Binding源时,可是A窗体内的控件可访问级别是private类型,那是就足以把这些控件只怕控件值作为窗体A的DataContext(那个天性是Public级其他)那样就能够暴露数据了。

印象的说,那时候外层的多少就一定于1个数额的“至高点”,只要把成分放上去,外人就可以看见。别的DataContext本身就是2个依靠属性,我们可以使用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成分在条款容器和数据成分之间创设起涉嫌,让大家来看1个例证:

UI代码如下:

 

[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.         </StackPanel>  
  12.     </Grid>  
  13. </Window>  

 

窗体运维效果如下图:

图片 50

我们要落成的意义就是把List<Student>的汇集作为ListBox的ItemSource,让ListBox显示学员的Name,并采取TextBox显示当前入选学员的Id,为了落实那么些作用,我们要求在窗体的构造函数中加上几行代码:

 

[csharp] view
plain
copyprint?

 

  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这一个单词了呢?那表达它是2个路线。当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—-就类似给多少穿上了三个粗略的衣服一样。至于什么是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设定了帕特h而从未点名Source,紧接那就把它关系到了TextBlock上。显著,要想获取Source,那个Binding必要向树根方向搜索包含_displayMemberPath钦命属性的DataContext。

**最终大家再看三个显得为多少设置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>  

运行效果图:

 

图片 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控件来显示3个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是1个ViewBase对象,所以,GridView可以做为ListView的View来使用而无法看做独立的控件来行使。那里运用理念是整合形式,即ListView有二个View,不过关于是GridView如故其它品类的View,由程序员自个儿选取—-近日唯有贰个GridView可用,估量微软在此间还会有增添。其次,GridView的故事情节属性是Columns,那本天性是GridViewColumnCollection类型对象。因为XAML协助对情节属性的简写,可以省略<GridView.Columns>那层标签,直接在GridView的始末部分概念三个<GridViewColumn>对象,GridViewColumn中最要紧的二个属性是DisplayBinding(类型是BindingBase),使用那一个天性可以钦点这一列使用什么的Binding去关联数据——那与List博克斯有点不相同,ListBox使用的是DisplayMemberPath属性(类型是string)。若是想用更扑朔迷离的布局来代表这一标题或数量,则可为GridViewColumn设置HeadTemplate和CellTemplate,它们的品类都以DataTemplate。

运作效果如下:

图片 53

后台代码如下:

 

[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属性的时候,并把2个ItemSource与2个既没有点名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设置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文本是一组文本消息,我们要把它显示在多个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. }  

程序运营效果如下:

 

**图片 54

**

XMLDataProvider还有2个名为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章节从此再回到便会明白于胸。

程序运转效果如下图:

图片 55

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

至3.0本子起首,.NET Framework最先协助LINQ(Language-Intergrated Query
 
语言集成查询),使用LINQ,大家可以便宜的操作集合对象、DataTable对象和XML对象不必动辄不动把一些层foreach循环嵌套在一块儿却只是为了做到2个很粗略的任务。

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

先创建2个名为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.         }  

 

 

程序运营效果如下图:

**图片 56

**

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类。随便新建一个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大家会看出如下界面:

 

图片 57

因此那一个顺序大家可以通晓到ObjectDataProvider对象和它被打包的对象关系如下图:

图片 58

 

刺探了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>  

图片 59

 

以此程序已毕的效应是,小编在前多个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类的功力是包裹一个以艺术揭发数据的对象,那里大家先创设了三个ObjectDataProvider的目的,然后用2个Caculate对象为其ObjectInstance对象赋值—那就把3个Caculate对象包装在了ObjectDataProvider里面。还有别的几个办法来创制被卷入的靶子,那就是报告包装对象被装进对象的门类和希望调用的构造器,让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只是对第②个的翻版,只是把帕特h属性指向了第③个因素。第多个binding依旧使用ObjectDataProvider作为Source,但运用“.”作为Path—-前边讲过,当数据源本人就是数额的时候就用“.”来做为Path,在XAML中”.”可以不写。

注意:

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

最后几行就是将Binding对象关系到1个TextBox对象上。程序运营效果如下:

图片 60

一般意况下多少从那边来,什么地方就是Binding的Source,数据到何地去,哪个地方就是Binding
的Target。按这一个理论,前八个TextBox应该是ObjcetDataProvider的源,而ObjcetDataProvider对象又是终极多个TextBox的源。但其实,八个TextBox都是ObjcetDataProvider作为数据源,只是前多个在数码流向上做了限制,那样做的原委不外乎有多少个:

壹 、ObjcetDataProvider的MethodParameter不是器重属性,无法作为Binding的对象。

二 、数据驱动UI理念须求我们尽量的运用数据对象作为Binding的Source而把UI当做Binding的Target。

1.3.12    使用Binding的RelativeSource

当2个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>  

界面运营结果如下:

 

图片 61

咱俩把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从本人的第贰层依次向外找,找到第二个Grid类型对象后把它看成自个儿的源。运营效果如下图:

 

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

 

[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}}”  

运营效果如下:

 

图片 63

比方TextBox须要关联自己的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}}”  

运作效果如下图:

 

图片 64

RelativeSource类的Mode属性是RelativeSourceMode枚举,它的值有:PriviousData、TemplatedParent、Self和FindAncestor。RelativeSource还有三个静态属性:PriviousData、Self、TemplatedParent,它们的连串是RelativeSource类。实际上那三个静态属性就是创设二个RelativeSource的实例、把实例的Mode设置为相对应的值,然后回来这几个实例。之所以准备那三个静态属性是为了在XAML代码里面一向得到RelativeSource实例。

在DataTemplate中时时用到这那2个静态属性,学习DataTemplate的时候请小心它们的施用办法。

1.4      binding对数据的转移和校验

面前大家已经知道Binding的效益就是架在Source和Target之间的大桥,数据可以在那座桥梁的支援下去流通。就像是现实社会中桥梁须求安装安检和关卡一样,Binding那座桥上也足以设置关卡对数码举办求证,不仅如此,假设Binding两端须求差别的数据类型的时候大家还是能够为数据设置转换器。

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

1.4.1          Binding的数码校验

Binding的ValidationRules属性是Collection<ValidationRule>,从它的名称和数据类型大家可以得知可以为每一种Binding设置两个数据校验条件,每三个规则是二个ValidationRule对象。ValidationRule是贰个抽象类,在选择的时候大家必要创建它的派生类并贯彻它的Validate方法的重返值是ValidateionResult类型对象,假若通过验证,就把ValidateionResult对象的IsValidate属性设为true,反之,则必要将IsValidate设置为false并为其ErrorContent属性设置3个体面的音讯内容(一般是字符串)。

下边这么些顺序的UI绘制二个TextBox和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>  

为了拓展校验,我们准备3个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里头的值的时候程序平常化突显,但是输入区间之外的值的时候Text博克斯会呈现为革命边框,表示值是荒谬的,不或者传值给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
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指示用户,如下图:

 

图片 69

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卡宴I(亦是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的景况被映射为图标,那多少个图标已经被作者放入项目中,如图:

 

图片 70

并且飞机的State属性在UI里面被映射为CheckBox。因为存在上述三种炫耀关系。大家需求提供三个Converter:三个有Categroy类型单向转换为string类型(XAML会把string解析为图片财富),另3个是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,如图:

 

图片 71图片 72

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

图片 73

1.5   MultiBinding(多路Binding)

有时UI必要显示的数额来源不止五个数额来源于决定,那几个时候就须要动用MultiBinding,即多路绑定。MultiBinding与Binding一样均以BindingBase为基类,约等于说,凡是能用Binding的场合都能使用MultiBinding。MutiBinding具有五个Bindings的本性,其项目是Connection<BindingBase>,通过那本性格,MultiBinding把一组Binding对象聚合起来,处在这一个Binding结合中的对象足以拥有本身的多大校验和转换机制。它们集聚起来的多寡将一并决定传往MultiBinding目标的数量。如下图:

图片 74

考虑这么二个需要,有一个用以新用户注册的UI(几个TextBox和三个Button),还有如下一些限量:

 

  • 先是,二个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. }  

程序运营效果如图:

 

图片 75 
  图片 76

小结:

WPF的核心理念是变古板的UI驱动数据变成数据驱动UI,支撑那一个意见的基础就是本章讲的Data
Binding和与之有关的数目校验和多少转换。在采取Binding的时候,最重大的就是安装它的源和途径。

 

 

Data Binding到此讲解截止。

相关文章