C++[转]深入浅出WPF(7)——数据的绿色通道,Binding

本文转自:http://liutiemeng.blog.51cto.com/120361/95273

小序:

怎一直打2蹦到7啊?!啊哦,实在是腼腆,最近实在是不过忙碌了,忙的故为非常简单——自己的艺最好差了,还有很多物一旦效仿呀。门里门外,发现专业程序员非常主要之一律件技术是读别人写的代码,这项技能甚至于自己写代码更要紧。Anstinus同学就是朗诵代码的巨匠,我形容的代码他拘留片目就亮怎么回事了,并且能够立刻改,而异的代码我念了一点龙还不明白凡是怎么回事儿呢。

2顶7中间是留XAML语言基础的,有些文章都抢写好了,但如自己对她不顺心,是绝对免见面停放网上来之。同时,最近发生过多情人又于催我朝生写,情急之下,只好把最好要害之几省赶下、先挂上来。

从而,毫不夸张地说,从本篇文章由联网下去的几乎首文章几乎可说凡是WPF的核心内容,非常重大。这几乎首文章分别介绍了Binding、Dependency Property、Routed Event &
Command
顶内容。精彩不绝,敬请关注!

正文:

每当念新物的时候,人们总是习惯以它同和谐早就了解的原始有学问去开比较,这样才控制得抢、记忆深刻。所以,经常发生情侣咨询我:“WPF与Windows
Form最充分的分别是呀?请用极端简单易行的说话告诉自己。”OK,这个题目问底雅好——看上去WPF与WinForm最深的区分像是眼前说的怪XAML语言,但XAML只是单外表现象,WPF真正引人入胜、使之与WinForm泾渭分明的特性就是是——“数据让界面”。围绕着是基本,WPF准备了过多定义相当前卫的技巧,其中囊括也界面准备的XAML、为底色数据准备的Dependency
Property和也消息传递准备的Routed Event & Command。

“数据令界面”,听起来有点抽象。用白话解释(中文白话似乎总为达到无了台面、更非克为书里描写,而老外的题里也可白话连篇)就是——数据是脚、是心脏,数据易了当表层的UI就见面随着变、将数据表现给用户;如果用户改了UI元素上的值,相当给通过UI元素直接改动了底部的数目;数据处于核心身份,UI处于依附地位。这样一来,数据是程序的发动机(驱动者)、UI成了几无含其他逻辑专供用户观察数及改数据的“窗口”(被驱动者)。

 顺就插一句子,如果您是平位WinForm程序员,“数据让界面”一开始会受您倍感不顶习惯。比如,在WinForm编程时,如果想对ListBox里的Item排序,我们见面直接去排列这些Item,也就是是本着界面进行操作,这在WPF里就不行了——实际上,在WPF里以界面完全是由数控制的(甚至连界面元素的排序),所以,我们无非待用脚数据排序,作为界面的Items也尽管以数据的教下小宝宝地解除好程序了。

这就是说,数据是怎么样从底部传递到界面的吗?我们今天之台柱,Binding同学,就如出演啦!

浅显话Binding

Binding同学最近死不开心,是因它们的汉语名字“很暴力”——绑定。我怀疑,最早的翻译也尚未什么标准而按,大概是为此了谐音吧!这无异谐音不要紧,搞的炎黄程序员就起接触摸不彻底头脑了。“绑”是扎的意,再添加一个“定”字,颇多了一些“绑在共同、牢不可分”的发。而实质上为?Binding却是个地地道道的松耦合的涉嫌!

遵在生拙见,Binding译为“关联”是更当不过了。在英语词典里,也确发生这同词条。关联呢,无需多提,人人都掌握凡是“之间有些干”的意。Data
Binding也尽管无应重给“数据绑定”了,应该称为“数据涉嫌”,意思是说,在数量和界面(或其它数据)之间具有某些关乎及联动。

切切实实到WPF中,Binding又是何许一种植关系及联动为?就如咱的慌题目一样——Binding就是数码的“绿色通道”。“绿色通道”代表正“直接”和“快速”,Binding就是如此。

于咱们分享一个幽默的事例,请看下面的截图:

C++ 1

此处是少单TextBox和一个Slider组成的UI,现在客户之急需是——当Slider的滑块移动时,上面很TextBox里显示Slider的Value;反过来,当在地方十分TextBox里输入合适的价值后,鼠标焦点移开后,Slider的滑块也要滑到相应的岗位上。

立在一个WinForm程序员的角度去考虑,他会开如此几起事情:

  1. 响应slider1的ValueChanged事件,在事件处理函数中于textBox1显示slider1底Value 
  2. 响应textBox1的LostFocus事件,把textBox1的Text转换成屡价,并赋值给slider1

注意了!这就是一流的“非数据驱动界面”的考虑。为什么也?

当我们应slider1的ValueChanged事件频仍,我们只要之是slider1的Value这个价值,这时候,slider1处于核心位置、是数的“源”(Source);当我们应textBox1的LostFocus事件时,我们要之是她的Text属性值,这时候,textBox1以成了数据的source。也就是说,在这种拍卖方法吃,数据尚未永恒的“源”,两独UI元素是对顶的、不在谁起属于哪个之题目。换句话说:它们中间是“就行论事”,并不曾呀“关联”。

属下,让咱感受一下“绿色通道”的霎时!

上述例子的XAML源代码如下:

view
plaincopy to
clipboardprint?

  1. <Window x:Class=”BindingSample.Window1″  
  2.     xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”  
  3.     xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”  
  4.     Title=”http://blog.csdn.net/FantasiaX” Height=”300″ Width=”300″>  
  5.     <Window.Background>  
  6.         <LinearGradientBrush StartPoint=”0,0″ EndPoint=”1,1″>  
  7.             <GradientStop Color=”Blue”  Offset=”0.3″/>  
  8.             <GradientStop Color=”LightBlue” Offset=”1″/>  
  9.         </LinearGradientBrush>  
  10.     </Window.Background>  
  11.     <Grid>  
  12.         <TextBox Height=”23″ Margin=”10,10,9,0″ Name=”textBox1″ VerticalAlignment=”Top” />  
  13.         <TextBox Height=”23″ Margin=”10,41,9,0″ Name=”textBox2″ VerticalAlignment=”Top” />  
  14.         <Slider Height=”21″ Margin=”10,73,9,0″ Name=”slider1″ VerticalAlignment=”Top” Maximum=”100″ />  
  15.     </Grid>  
  16. </Window>  

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="http://blog.csdn.net/FantasiaX" Height="300" Width="300">
    <Window.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="Blue"  Offset="0.3"/>
            <GradientStop Color="LightBlue" Offset="1"/>
        </LinearGradientBrush>
    </Window.Background>
    <Grid>
        <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
        <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
        <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
    </Grid>
    

删除那些花里呼哨的饰物后,最紧要的只有脚3推行(而实在第2推行很textBox2单独是为吃鼠标的纽带有个去处):

view
plaincopy to
clipboardprint?

  1. <Grid>  
  2.     <TextBox Height=”23″ Margin=”10,10,9,0″ Name=”textBox1″ VerticalAlignment=”Top” />  
  3.     <TextBox Height=”23″ Margin=”10,41,9,0″ Name=”textBox2″ VerticalAlignment=”Top” />  
  4.     <Slider Height=”21″ Margin=”10,73,9,0″ Name=”slider1″ VerticalAlignment=”Top” Maximum=”100″ />  
  5. </Grid>  

    <Grid>
        <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
        <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
        <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
    </Grid>
    

 

然后,我就需要在第1履代码上做一个微小修改,就能够形成WinForm中得为此半只事件响应、十基本上行代码才能够不辱使命的事情:

view
plaincopy to
clipboardprint?

  1. <Grid>  
  2.     <TextBox Height=”23″ Margin=”10,10,9,0″ Name=”textBox1″ VerticalAlignment=”Top” Text=”{Binding ElementName=slider1, Path=Value}”/>  
  3.     <TextBox Height=”23″ Margin=”10,41,9,0″ Name=”textBox2″ VerticalAlignment=”Top” />  
  4.     <Slider Height=”21″ Margin=”10,73,9,0″ Name=”slider1″ VerticalAlignment=”Top” Maximum=”100″ />  
  5. </Grid>  

    <Grid>
        <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=slider1, Path=Value}"/>
        <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
        <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
    </Grid>
    

有心人的汝,一定一眼就看仅多矣这么平等句子话:Text=”{Binding
ElementName=slider1, Path=Value}”

即词话的意是说:Hi,textBox1,从此以后,你的Text属性值就跟slider1这个UI元素的Value属性值关联上了,Value变的时节你的Text也如就变。

这儿的功效是——你拖动Slider的滑块,textBox1就算会显示值(双精度,0到100以内);你在textBox1里输入一个0至100期间的数字,当把鼠标移动到textBox2里不时,slider1的滑块会跳到对应的价上去,如图:

C++ 2 

C++ 3

非常简单是无是?请小心,这中间可含蓄了“数据驱动界面”的型哦!在此间,我们总把slider1的Value当成是数据源(Data
Source),而textBox1虽说是故来展示与修改数据的窗口(Data
Presenter)——slider1是主导,它的Value属性值将让textBox1的Text进行更改;人为改变textBox1的Text属性值,也会见让送回slider1的Value属性值上去。

是下被我们询问Data Binding的几乎单基本点概念了——

  1. 数据源(Data
    Source,简称Source):顾名思义,它是承保发数量的实业、是数的自、源头。把谁当数据源完全由程序员来支配——只要您想管其看成数据核心来采取。它可是一个UI元素、某个类的实例,也得以是一个成团(关于对聚集的绑定,非常重大,专门用同一篇稿子来谈谈的)。 
  2. 路(Path):数据源作为一个实体可能有着广大数据,你实际关注它的谁数值为?这个数值便是Path。就端的例证而言,slider1是Source,它有广大数码——除了Value之外,还有Width、Height等,但犹无是咱们所关注的——所以,我们拿Path设为Value。 
  3. 目标(Target):数据以传送到哪里去?这就是数额的目标了。上面这事例中,textBox1是数据的Target。有几许消非常上心:Target一定是数的接收者、被驱动者,但其不肯定是数额的显示者——也许她只有是多少联动中的均等缠——后面我们深受出了例子。 
  4. 关系(Binding):数据源与对象以内的坦途。正是这个通道,使Source与Target之间涉及了四起、使数据可知(直接或者间接地)驱动界面! 
  5. 设定关联(Set
    Binding):为Target指定Binding,并以Binding指于Target的一个性质,完成多少的“端对端”传输。

 绿色通道上的“关卡”:

 话说眼看就要交奥林匹克了,北京之各国大交通要道上也都提高了安检力度。微软同学为被Binding这长长的“绿色通道”准备了几鸣好实用的“关卡”。这些“关卡”的启闭与安装是经Binding的性能来就的。其中常用之有:

  • 一旦你想把“绿色通道”限制也“单行道”,那就设置Binding实例的Mode属性,它是一个BindingMode类型的枚举值,其中富含了TwoWay、OneWay和OneWayToSource几单价值。上面这例子中,默认地是TwoWay,所以才见面产生双向的数据传递。 
  • 假使用户提出如果textBox1的文书改变slider1的滑块立刻响应,那即便设置Binding的UpdateSourceTrigger属性。它是一个UpdateSourceTrigger类型枚举值,默认值是UpdateSourceTrigger.LostFocus,所以才见面在变走鼠标焦点之早晚更新数据。如果管其装为UpdateSourceTrigger.PropertyChanged,那么Target被提到的属性只要同改变,就立即传给Source——我们只要召开的无非是转了一个单词,而WinForm程序员这时候正头疼也,因为他需去把代码搬至其它一个事变响应函数中失。 
  • 一经Binding两端的数据类型不同等怎么处置?没关系,你可设置Binding的Converter属性,具体内容在下篇文章中讨论。 
  • 设若数据遭到起“易燃易爆”的未安全因素怎么处置?OK,可以设置Binding的ValidationRules,为它们长同样组“安检设备”(同样也于下篇文中讨论)。

在C#代码中设置Binding

XAML代码是这样简单,简单就那同样句子话。这不过免是个人等C#程序员、刨根问底之光可以善罢甘休的!

像地谈,Binding就如一个盒子,盒子里装了片电动用于过滤和控制数据,盒子两端各就一干净管,管子是由管壳和管芯构成的,看上去就比如下的希冀:

C++ 4

 

当脑子里出了如此一个影像之后,遵循下面的手续就是OK了:

  1. Source:确定谁目标作为数据源 
  2. Target:确定谁目标作为对象 
  3. Binding:声明一个Binding实例 
  4. 把同根管接到Source上并把管芯插在Source的Path上 
  5. 拿任何一样彻底管接到Target上连把管芯插在Target的联动性上

比方有必要,可以于3暨4期间设置Binding的“关卡”们。其实,第3步后的逐条不是定点的,只是这个手续比较好记——一概向右侧连接。所得结果看上去是如此:

C++ 5

 

本身猜测你或许会见问:“那个D.P.是啊呀?”

D.P.的完备是“Dependency
Property”,直译过来就是“依赖式属性”,意思是说它们好我是没价值的,它的价值是“依赖”在另对象的属于性值上、通过Binding的传递及转移而得来之。表现在例子里,它就是Target上之叫数所让的联动性了!

此间是等价格的C#代码,我将她形容在了Window1的构造函数里:

view
plaincopy to
clipboardprint?

  1. public Window1()   
  2. {   
  3.     InitializeComponent();   
  4.   
  5.     // 1. 自我打算用slider1作为Source
      
  6.     // 2. 我打算因此textBox1当作Target
      
  7.     Binding binding = new Binding();   
  8.     binding.Source = this.slider1;   
  9.     binding.Path = new PropertyPath(“Value”);
      
  10.     this.textBox1.SetBinding(TextBox.TextProperty, binding);            
      
  11. }  

    public Window1()
    {

    InitializeComponent();
    // 1. 我打算用slider1作为Source
    // 2. 我打算用textBox1作为Target
    Binding binding = new Binding();
    binding.Source = this.slider1;
    binding.Path = new PropertyPath("Value");
    this.textBox1.SetBinding(TextBox.TextProperty, binding);            
    

    }

诙谐的凡,Source端的操作,接管子和插管芯分两步,而Target端也是当SetBinding方法吃千篇一律步成功。注意啊,TextBox.TextProperty就是一个Dependency
Property的庐山真面目!关于Dependency
Property的文档业已做到,我拿择一黄道吉日挂拿出来:p

点的代码稍有简化的后路,那就算是管Path的设定转移至Binding的布局中错过:

view
plaincopy to
clipboardprint?

  1. public Window1()   
  2. {   
  3.     InitializeComponent();   
  4.        
  5.     // 1. 本身打算因此slider1作为Source
      
  6.     // 2. 本人打算就此textBox1作为Target
      
  7.     Binding binding = new Binding(“Value”);
      
  8.     binding.Source = this.slider1;   
  9.     this.textBox1.SetBinding(TextBox.TextProperty, binding);            
      
  10. }  

    public Window1()
    {

    InitializeComponent();
    
    // 1. 我打算用slider1作为Source
    // 2. 我打算用textBox1作为Target
    Binding binding = new Binding("Value");
    binding.Source = this.slider1;
    this.textBox1.SetBinding(TextBox.TextProperty, binding);            
    

    }

如此做的功利是——随便你于binding指定一个Source,只要这个Source有“Value”这个特性,binding就会见活动取它的值并传给Target端。

俺们还好啊binding设些“关卡”:

view
plaincopy to
clipboardprint?

  1. public Window1()   
  2. {   
  3.     InitializeComponent();   
  4.   
  5.   
  6.     // 1. 我打算因此slider1作为Source
      
  7.     // 2. 自打算就此textBox1作Target
      
  8.     Binding binding = new Binding(“Value”);
      
  9.     binding.Source = this.slider1;   
  10.     binding.Mode = BindingMode.TwoWay;   
  11.     binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
      
  12.     this.textBox1.SetBinding(TextBox.TextProperty, binding);            
      
  13. }  

    public Window1()
    {

    InitializeComponent();
    // 1. 我打算用slider1作为Source
    // 2. 我打算用textBox1作为Target
    Binding binding = new Binding("Value");
    binding.Source = this.slider1;
    binding.Mode = BindingMode.TwoWay;
    binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    this.textBox1.SetBinding(TextBox.TextProperty, binding);            
    

    }

 还有一个细微提示:如果Source碰巧是一个UI元素,那么为不过拿binding.Source
= this.slider1;改写成binding.ElementName =
“slider1”;或者binding.ElementName = this.slider1.Name;

于定义数据源:

在我们项目组便的干活吃,经常要协调写一个近似,并且以她的实例当作数据源。怎样才能让一个接近成为“合格的”数据源呢?

假设诀就是:

  1.  为夫类似定义有Property,相当给为Binding提供Path 
  2. 叫这看似实现INotifyPropertyChanged接口。实现者接口的目的是当Source的属性值改变后通知Binding(不然人家怎么懂得源头的数据易了连进行联动共同呢?),好让Binding把数据传给Target——本质上还是使用事件机制来开,只是掩盖以底部、不用程序员去形容event
    handler了。

 让我们写一个这么的类:

view
plaincopy to
clipboardprint?

  1. <PRE class=csharp name=”code”>// 第一步:声明一个近似,准备必要之习性
      
  2.   
  3. public class Student    
  4. {   
  5.     private int id;
      
  6.     public int Id
      
  7.     {   
  8.         get { return id; }   
  9.         set { id = value; }   
  10.     }   
  11.   
  12.     private string name;   
  13.     public string Name
      
  14.     {   
  15.         get { return name; }   
  16.         set { name = value; }   
  17.     }   
  18.   
  19.     private int age;
      
  20.     public int Age
      
  21.     {   
  22.         get { return age; }   
  23.         set { age = value; }   
  24.     }   
  25.   
  26. }</PRE>  

view
plaincopy to
clipboardprint?

  1. // 第一步:声明一个接近,准备必要之属性
      
  2.   
  3. public class Student    
  4. {   
  5.     private int id;
      
  6.     public int Id
      
  7.     {   
  8.         get { return id; }   
  9.         set { id = value; }   
  10.     }   
  11.   
  12.     private string name;   
  13.     public string Name
      
  14.     {   
  15.         get { return name; }   
  16.         set { name = value; }   
  17.     }   
  18.   
  19.     private int age;
      
  20.     public int Age
      
  21.     {   
  22.         get { return age; }   
  23.         set { age = value; }   
  24.     }   
  25.   
  26. }  

    // 第一步:声明一个好像,准备必要之性
    public class Student
    {

    private int id;
    public int Id
    {
        get { return id; }
        set { id = value; }
    }
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; }
    }
    

    }

 接下来就以INotifyPropertyChanged接口“武装”这个近乎了,注意,这个接口在System.ComponentModel名称空间被:

view
plaincopy to
clipboardprint?

  1. // 第二步:实现INotifyPropertyChanged接口
      
  2.   
  3. public class Student : INotifyPropertyChanged
      
  4. {   
  5.     public event PropertyChangedEventHandler PropertyChanged; // 这个接口就包含一个波而就
      
  6.   
  7.     private int id;
      
  8.     public int Id
      
  9.     {   
  10.         get { return id; }   
  11.         set  
  12.         {   
  13.             id = value;   
  14.             if (this.PropertyChanged != null)
      
  15.             {   
  16.   
  17.                 this.PropertyChanged.Invoke(thisnew PropertyChangedEventArgs(“Id”)); // 通知Binding是“Id”这个特性之值改变了
      
  18.             }   
  19.         }   
  20.     }   
  21.   
  22.   
  23.     private string name;   
  24.     public string Name
      
  25.     {   
  26.         get { return name; }   
  27.         set  
  28.         {   
  29.             name = value;   
  30.             if (this.PropertyChanged != null)
      
  31.             {   
  32.                 this.PropertyChanged.Invoke(thisnew PropertyChangedEventArgs(“Name”)); // 通知Binding是“Name”这个特性的值改变了
      
  33.             }   
  34.         }   
  35.     }   
  36.   
  37.     private int age;
      
  38.     public int Age
      
  39.     {   
  40.         get { return age; }   
  41.         set { age = value; } // Age的价改变时莫开展通报
      
  42.     }  

    // 第二步:实现INotifyPropertyChanged接口
    public class Student : INotifyPropertyChanged
    {

    public event PropertyChangedEventHandler PropertyChanged; // 这个接口仅包含一个事件而已
    private int id;
    public int Id
    {
        get { return id; }
        set
        {
            id = value;
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Id")); // 通知Binding是“Id”这个属性的值改变了
            }
        }
    }
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); // 通知Binding是“Name”这个属性的值改变了
            }
        }
    }
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; } // Age的值改变时不进行通知
    }
    

view
plaincopy to
clipboardprint?

  1. OK,此时,你可以品尝利用Student类的实例作为数据源了!  

    OK,此时,你可以尝尝运用Student类的实例作为数据源了!

自打定义数据目标:

向而非来,非礼也;来若无为,亦非礼也——《礼记·曲礼》

略知一二了何等定义数据源,一定想同一鼓作气再定义一个数量目标吧?让咱们回想一下:Binding接在Target一端的管,它的管芯是插在一个Dependency
Property上之!所以,在我们熟悉Dependency
Property之前,恐怕只能动用现成的.NET对象来担任Target了!

故,敬请关注《深入浅出WPF》系统的接续文章!

 

 http://liutiemeng.blog.51cto.com/120361/95275

小序:

今中午凭着罢饭回工位的途中,和咱们组资深的Level
2技术支持肖先生且了几乎句。我跟肖老师说,最近自家于习Binding,肖先生说——那可是个好东西!因为如果在程序中动用了Binding,当起谬误的下,比较难以给调试。道理很简单——以前使用事件(C++里是回调)的时节,能一目了然地于事件处理函数里去跟调试,现在利用Binding,数据源和UI之间是同样付出封闭的“管道”,在代码中充分不便见到她们是当何关联上之、出了问题也不知道在哪里拦截、设断点。

当时真是只问题!我又失去请教了别的同事。Allen同学告知我,在Binding和数量目标(的Dependency
Property)有局部事变,会于数额产生传的下吃激起,或者当Binding的Converter和Validator上下下功夫。看来Binding值得研究之地方还确实多呀!

文章的字数毕竟有限,我不得不捡工作当中用的极度多的来介绍。那么,我还有如何东西需要介绍为?

  • 受多少“为我所用”的Converter 
  • 深受数据“干干净净”的Validation 
  • 聚拢控件与聚集数据的Binding 
  • 偷懒专用的数据中转站——DataContext

希望我之做事能吃大家长起一个地道的就学框架——全面细致的内容一直在MSDN里,请大家看之上会轻松局部。

正文: 

了不起用数码的Converter

齐篇文已经说明,Binding就是数据源与目标以内的“关联”。大多数情况下,数据由Source到Target以及从Target返回Source都是“直来直去”的,但略场景却需要我们对数据做来转换才能够为我所用。举两独独立的例子:

  • 若数额源里的价是Y和N,如果是Y,那么UI上的CheckBox就被勾选,否则即非勾选,这就是用我们管string(也许是char)类型的数码易成bool?类型又以。如果Binding是TwoWay的,CheckBox的勾选操作还会将值传回数据源。 
  • 若果“评论内容”TextBox里没内容,则“提交”Button不可以点击。这是独独立的OneWay数据Binding,因为只有TextBox去影响Button的份儿。具体怎么促成,大家好优先猜猜;)

相思要落实就好像的转换,就待为Binding这个“绿色通道”设置“关卡”,这里我们之所以到的卡子就是“数据转换器”(Data
Converter)。Converter实际上就是一个看似,它这类似闹个要求——它用贯彻IValueConverter这个接口。这个接口的内容非常简单——只生零星只法子,它们分别是:

  • Convert方法:按照卿的求,把从数据源传来的多寡变动成为你想只要之数据——至于是加减乘除还是炒炒炸炖,那就假设扣押您怎么落实函数体了 
  • ConvertBack方法:如果Binding是TwoWay的,那么数量目标会转传经用户改后底数据,这时候若不怕只能把多少易回数据源里的格式——大多数状况下,它是Convert方法的逆运算,具体情况还要具体分析。(不过,熟饭估计怎么在吗换不成生米了,呵呵~~)

 下面是率先独例子的主干代码,我来平等步一步实现。

第一步:先声明一个类似。我之惯是因此Converter开头,后缀是“源类型2目标项目”,这里的“2”是“to”的意思。

 

view
plaincopy to
clipboardprint?

  1. class ConverterYN2TF   
  2. {   
  3.   
  4. }  

    class ConverterYN2TF
    {
    }

亚步:让这个类似实现IValueConverter接口。这里出个使用VS2008底小窍门——在类名后写上“:
IValueConverter”后,按下键盘上的“Shift+Alt+F10”会弹出VS2008底智能菜单,选择之中的率先桩“实现IValueConverter的计”,VS2008会面自行为咱别需要实现的方法体:

view
plaincopy to
clipboardprint?

  1. class ConverterYN2TF : IValueConverter
      
  2. {  
  3.     #region IValueConverter Members
      
  4.   
  5.     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  6.     {   
  7.         throw new NotImplementedException();
      
  8.     }   
  9.   
  10.     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  11.     {   
  12.         throw new NotImplementedException();
      
  13.     }  
    1.     #endregion   
  14. }  

    class ConverterYN2TF : IValueConverter
    {

    #region IValueConverter Members
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    #endregion
    

    }

老三步:添加Attribute。这步不是必备的,但增长有是发生益处的——告诉Converter数据的源类型与对象项目各是呀。值得注意的是,CheckBox的IsChecked属性是bool?类型的(可空bool类型),意思是说可以是True/False/Null三栽价值,表现在UI上虽是勾选/不勾选/中间态。如果想叫CheckBox能显得中间态,需要拿它的IsThreeState属性设为True。

view
plaincopy to
clipboardprint?

  1. [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标项目是bool?
      
  2. class ConverterYN2TF : IValueConverter
      
  3. {  
    1.     #region IValueConverter Members
        
  4.   
  5.     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  6.     {   
  7.         throw new NotImplementedException();
      
  8.     }   
  9.   
  10.     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  11.     {   
  12.         throw new NotImplementedException();
      
  13.     }  
    1.     #endregion   
  14. }  

    [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标项目是bool?
    class ConverterYN2TF : IValueConverter
    {

    #region IValueConverter Members
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    #endregion
    

    }

季步:实现就片独道。在上马着手前,我们先分析一下立即简单单艺术的参数和归值。

首先,这有限单点子的参数与归值都是object类型的,之所以这样做,是因接口的设计者并不知道你要传播和扩散的多少是呀项目的,只好用其“绝对是”的基类——object了。

说不上,对于Convert方法吧, value是从数据源传来的数码,返回值是移好后发送给数据目标的多少。对于ConvertBack方法正好反过来,value是打数额目标(比如UI)传回到的数据,返回值是要和数据源匹配的数。

重复,偶尔我们见面为此到parameter那个参数。比如当更换某些数据的时光,我们需要靠一些其他的外部数据来帮衬我们的数目易,这时候就好以parameter上打主意了。如果想传多单参数的讲话,可以将这些参数打包改成数组或者class/struct等数据结构再招进。在咱们做事之代码中之所以到过相同软parameter,我呢自家之Converter类准备了一个牵动参数的构造函数,把外部的扶数据传给Converter

终极,如果您的Binding是OneWay的,那么恭喜你——你的ConvertBack函数体随便怎么落实还好——因为它不容许为调用。

好的切近是如此的:

view
plaincopy to
clipboardprint?

  1. [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标项目是bool?
      
  2. class ConverterYN2TF : IValueConverter
      
  3. {   
  4.     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  5.     {   
  6.         string str = System.Convert.ToString(value);
      
  7.         switch (str)   
  8.         {   
  9.             case “Y”:   
  10.                 return true;
      
  11.             case “N”:   
  12.                 return false;
      
  13.             default:   
  14.                 return null;
      
  15.         }   
  16.     }   
  17.   
  18.     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      
  19.     {   
  20.         bool? b = System.Convert.ToBoolean(value);
      
  21.         switch (b)   
  22.         {   
  23.             case true:   
  24.                 return “Y”;   
  25.             case false:   
  26.                 return “N”;   
  27.             default:   
  28.                 return “Null”;   
  29.         }   
  30.     }   
  31. }  

    [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标项目是bool?
    class ConverterYN2TF : IValueConverter
    {

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string str = System.Convert.ToString(value);
        switch (str)
        {
            case "Y":
                return true;
            case "N":
                return false;
            default:
                return null;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool? b = System.Convert.ToBoolean(value);
        switch (b)
        {
            case true:
                return "Y";
            case false:
                return "N";
            default:
                return "Null";
        }
    }
    

    }

采用这类似的办法是将Binding实例的Converter属性设置也之看似的一个实例:

view
plaincopy to
clipboardprint?

  1. checkBox1.IsThreeState = true;   
  2. Binding binding = new Binding(“Text”);
      
  3. binding.Source = textBox1;   
  4. binding.Converter = new ConverterYN2TF(); // 设定Converter
      
  5. this.checkBox1.SetBinding(CheckBox.IsCheckedProperty, binding);  

    checkBox1.IsThreeState = true;
    Binding binding = new Binding(“Text”);
    binding.Source = textBox1;
    binding.Converter = new ConverterYN2TF(); // 设定Converter
    this.checkBox1.SetBinding(CheckBox.IsCheckedProperty, binding);

 

至于上面的亚独例,留给大家自己下手去落实吧。想同一纪念:怎样才能让Button的IsEnable属性与TextBox中文本的产生无涉及上也? 

 为数“干干净净”的Validation

又于咱来探视哪些对数码开展“安检”。 

率先,这里发生一个“霸王条款”——Binding看自数据源出去的数码还是“干净”的,所以未开展校验;只有从数目标回传的多寡才起或是“脏”的,需要校验。

说不上,对于一个Binding而言,Converter只能发出一个,而校验条件得以是少数个——它们存储于Binding的ValidationRules这个集合里。其实,数据校验与转移做的事宜多。

下让来一个例:我们盖一个Slider为数据源,它的滑块可以于Value=0滑到Value=100;同时,我们为一个TextBox为数量目标,并经Validation限制她不得不拿20届35内的数据传数据源。现实中等或许很少发生这样干的,我们这例子只是以求证校验的利用方法:)

一经要创建一个自定义的校验条件,需要声明一个像样,并受这看似派生自ValidationRule类。ValidationRule只出一个叫做也Validate的主意要我们兑现,这个法的返回值是一个ValidationResult类型的实例——这个实例携带着简单单消息:

  • bool类型的IsValid属性告诉Binding回传的多寡是否合法
  • object类型(一般是储存一个string)的ErrorContent属性告诉Binding一些信息,比如当前凡展开什么操作而产出的校验错误等等,一般我会把这些消息写上Log文件里

贯彻好的接近是这般的:

view
plaincopy to
clipboardprint?

  1. public class MyValidationRule : ValidationRule
      
  2. {   
  3.     public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
      
  4.     {   
  5.         double d = 0.0;   
  6.         if (double.TryParse((string)value, out d) && d >= 20 && d <= 35)
      
  7.         {   
  8.             return new ValidationResult(true, “OK”);
      
  9.         }   
  10.         else  
  11.         {   
  12.             return new ValidationResult(false, “Error”);
      
  13.         }   
  14.     }   
  15. }  

    public class MyValidationRule : ValidationRule
    {

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        double d = 0.0;
        if (double.TryParse((string)value, out d) && d >= 20 && d <= 35)
        {
            return new ValidationResult(true, "OK");
        }
        else
        {
            return new ValidationResult(false, "Error");
        }
    }
    

    }

以代码里这么以它:

view
plaincopy to
clipboardprint?

  1. Binding binding = new Binding(“Value”);
      
  2. binding.Source = slider1;   
  3. binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
      
  4. binding.ValidationRules.Add(new MyValidationRule()); // 加载校验条件
      
  5. textBox1.SetBinding(TextBox.TextProperty, binding);  

    Binding binding = new Binding(“Value”);
    binding.Source = slider1;
    binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    binding.ValidationRules.Add(new MyValidationRule()); // 加载校验条件
    textBox1.SetBinding(TextBox.TextProperty, binding);

程序执行起来然后的意义是这般的:

自我得以运用Slider滑发生从0到100底值来,也可以动用TextBox输入20暨35次的价;但当自己输入小于20或者超过35底数字与非数字时,值就无见面让染回到Slider(数据源),同时,TextBox还会为一个革命的边框圈起来为显示警告。至于警告的风骨,我们得以由定义,具体怎么定义我会在Style一节去叨叨。

C++ 6

 

TO BE CONTINUE…

下篇文中我们以介绍好实用的集合Binding与懒人的极爱——DataContext

 

小知识:什么是L2

CA有些同事(而且是C++比较牛的同事)是做Level
2的,也不怕是“二级技术支持”,Level
1是连接客户电话、对客户拓展支撑之——他们太要害的工作就是是当用户发现bug时用开心的口吻告诉他们:“Hi,that
a
feature:)”,呵呵,开单玩笑,实际上他们时给怒气冲冲、快要疯的客户。如果实在是单bug,那L1的同室等为弄不自然,这时候就要管bug提交给L2的同窗等了,L2的同窗等见面连夜改代码、解bug、出SP包……算是我们的“救火队员”了,公司之良好信誉离不上马他们的奋力。

 

http://liutiemeng.blog.51cto.com/120361/95283

小序:

看正在友好及亦然篇技术文章,屈指算来,已经月余没有动笔了——实在是勿像话。最近一来是忙碌工作,二来是兴趣点放在了设计模式上,而且尝试着将设计模式也“深入浅出”了一样把,当然啦,因为对design
pattern我哉是初学,在未曾经过大家检视之前我是勿敢将到blog里扔人即眼滴~~~现在类型组里由喵喵同学、美女燕、大马同学及小马同学一道push一个“设计模式沙龙”,大家一起上学和议论这些模式以及如何利用在我们的型里召开重构。等活动收尾后,我心头发生之了,就拿稿子放上:)

 

N久不动笔了……上回写到哪里了?呃~~~咱们继续吧!

 

正文

苟用相同句子话概括前几乎首关于data binding的稿子,那就是是:介绍了多少让(界面)开发的基本原理,以及如何以Binding类的实例连接数据源与数码显现元素、形成一定之binding(为了给多少中、安全,我们还得添加Converter和ValidationRule等附件)。

 

小心啊,我强调了转——是一定之binding哦!也就是说,一个binding实例一端是数据源、一端是见元素。现在题材来了:实际工作吃,我们操作的大部分数码还是集结,怎么进行“群体binding”呢?呵呵,这就是引出了我们今天底第一单topic——对聚集进行binding。

 

集合Binding揭秘

俺们怀念这样一个题目——如果自身产生一个List<Student>的实例,里面装在二十个Student对象,现在自我想吃一个ListBox显示有学生的Name,并且当集合中生出Student对象的Name发生反时,ListBox的Item也立刻显示出来,应该怎么开吧?

有人会说:那还不好收拾?做一个循环,按照集合元素的多少变化对应多之ListBoxItem,并拿每个ListBoxItem的Text属性(如果出)用Binding一针对性连日接到List中的Student对象上无纵结束了?

自我未曾尝试了这样实践不行,但自我了解,这违背了“数据驱动UI”的口径——请牢记,在WPF开发时,不至万无奈,不要去打UI元素的主见、不要将UI元素掺合进任何运算逻辑。拿地方的事例来说,手动地去生成ListBoxItem就早已超越了“数据驱动UI”的范围,是未适宜的作法。

OK,让咱省微软供的“正宗集合binding”吧!

率先我们得准备一个用来存放数据的集,对于这集有一个独特的求,那就是是,这个集一定要是促成了IEnumerable接口的聚众。为什么吧?原因非常粗略,实现了IEnumerable接口就表示这个集合里的因素是可枚举的,可枚举就象征这集合里的元素是跟一个种的(至少存有相同之父类),元素是和一个列的就算象征当每个元素中自还能够找到同样的性质。举个例子,如果一个落实了IEnumerable的集里装的凡Student元素,这就象征每个元素都产生像ID、Name、Age等性能,对于其余一个素我都不见面寻找不至ID、Name或者Age——不然就从未道“批量binding”了;如果一个贯彻了IEnumerable接口的聚合里除发Student对象,还有Teacher对象、Programmer对象,怎么处置呢?这时候,这个集肯定只能拿Student、Teacher、Programmer的一头基类来进行枚举了,假设它们的联合基类是Human,那Human至少会有Name和Age属性吧——我们得用这简单独特性去做binding的Path,而集合里的各级一个素都看作一个独自的数据源。

下面我受闹中心代码。

 

第一我们准备了一个Student类,包含StuNum、Name、Age三单特性,

view
plaincopy
to
clipboardprint?

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

    class Student
    {

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

    }

然后我们当Window的Grid元素里补充加一个ListBox,这个操作是以XAML文件里举行的:

 

 

view
plaincopy
to
clipboardprint?

  1. <WINDOW title=Window1 xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” Width=”300″ Height=”300″ xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” x:Class=”CollectionBinding.Window1″>  
  2.     <GRID>  
  3.         <LISTBOX Background=”LightBlue” Margin=”5″ Name=”listBox1″ />  
  4.     </GRID>  
  5. </WINDOW><PRE></PRE>  

显出来的效能是这么的:

 

C++ 7

 

连着下,我们应用集合binding,让ListBox把学生的讳显示出。为了便利起见,我拿逻辑代码写于了Window的构造函数里,请大家小心——做项目的下如果尽量保持构造函数里之“干净”,很多博艰苦耦合都是未小心在构造函数里“创造”出来的。

 

  1. //水的真正谛出品
  2. // [url]http://blog.csdn.net/FantasiaX\[/url\]

  3. public Window1()

  4. {
  5.     InitializeComponent();
  6.     List<Student> stuList = new List<Student>() 
  7.     {
  8.         new Student{StuNum=1, Name=”Tim”, Age=28},
  9.         new Student{StuNum=2, Name=”Ma Guo”, Age=25},
  10.         new Student{StuNum=3, Name=”Yan”, Age=25},
  11.         new Student{StuNum=4, Name=”Xaiochen”, Age=28},
  12.         new Student{StuNum=5, Name=”Miao miao”, Age=24},
  13.         new Student{StuNum=6, Name=”Ma Zhen”, Age=24}
  14.     };
  15.     this.listBox1.ItemsSource = stuList;

  16.     this.listBox1.DisplayMemberPath = “Name”;

  17. }

生效地游说,你马上就能收看成效:

 

C++ 8

 

实在,最实用的就是最后两句代码:

this.listBox1.ItemsSource = stuList;一词的意是报告ListBox说:stuList这个集合里的因素就是你的条规啦!也就是说,stuList就同一于listBox1.Items了。集合对聚集,意味着两个集合里的素呢以各个对应。

明朗,stuList集合里的元素是ListBox.Items集合里元素的数据源,两个集合里的因素一一对应。

还有一样词,this.listBox1.DisplayMemberPath = “Name”;,是报告ListBox说,你的每个条目不是设来得点东西被用户看吗?那尔就是显得“Name”属性之值吧!

汝或许会见问:它怎么知道失去追寻Student对象的Name属性呀?你想呀,前面说过,能用来做数据源的集合一定实现了IEnumerable接口(List<>就实现了此接口),也就是说,我得枚举出一个一个之Student对象,又盖每个Items里的因素还和stuList里之一个Student对象一一对应、每个Student对象自然起Name属性,so,很轻就Binding上了。

深好玩儿,是吧!让自己看就往下看——常见的客户需要是:在ListBox里展示一个哟事物的称谓,点上然后,在一个精心表单里显示有各个一个条文的详细信息。让咱们改造一下咱们的次第!

 

先是,我修改了UI,XAML如下:

 

  1. <Window x:Class=”CollectionBinding.Window1″

  2.     xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

  3.     xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

  4.     Title=”水之真谛” Height=”300″ Width=”300″>

  5.     <StackPanel>
  6.         <ListBox Name=”listBox1″ Margin=”5″ Height=”150″ Background=”LightBlue”/>

  7.         <TextBox Name=”stuNumTextBox”  Margin=”5″ Background=”LightGreen”/>

  8.         <TextBox Name=”nameTextBox”  Margin=”5″ Background=”LightGreen”/>

  9.         <TextBox Name=”ageTextBox”  Margin=”5″ Background=”LightGreen”/>

  10.     </StackPanel>

  11. </Window>

作用使图:

 

C++ 9

 

若客户之求比较简单,就是选中ListBox中的一样件后,只查其的某一个性质(比如选中一个学员的讳,只看他的学号),那就上我们出只简易的方式——每个成功男人的暗还来一个家里;每个显示出来的Text背后还掩藏在一个Value!

 

  1. public Window1()
  2. {
  3.     InitializeComponent();
  4.     List<Student> stuList = new List<Student>() 
  5.     {
  6.         new Student{StuNum=1, Name=”Tim”, Age=28},
  7.         new Student{StuNum=2, Name=”Ma Guo”, Age=25},
  8.         new Student{StuNum=3, Name=”Yan”, Age=25},
  9.         new Student{StuNum=4, Name=”Xaiochen”, Age=28},
  10.         new Student{StuNum=5, Name=”Miao miao”, Age=24},
  11.         new Student{StuNum=6, Name=”Ma Zhen”, Age=24}
  12.     };
  13.     this.listBox1.ItemsSource = stuList;

  14.     this.listBox1.DisplayMemberPath = “Name”;

  15.     this.listBox1.SelectedValuePath = “StuNum”;
  16.     this.stuNumTextBox.SetBinding(TextBox.TextProperty, new Binding(“SelectedValue”) { Source = this.listBox1 });
  17. }

this.listBox1.SelectedValuePath = “StuNum”;这词代码的意是说:如果ListBox里的某某平等久Item被选中了,那么ListBox就失去找到与当时漫漫Item所对应之多少源集合里的异常元素,并把这个元素的StuNum属性的价将出去,当作当前入选Item的值。最后一句子是将TextBox的Text依赖属性关联到listBox1的SelectedValue上。运行起来的功用就是:

 

C++ 10

 

如客户要求出示有消息,那这种“简装版”的binding就懵了,因为它只能以到一个值。这时候,我们要这样做:

 

  1. public Window1()
  2. {
  3.     InitializeComponent();
  4.     List<Student> stuList = new List<Student>() 
  5.     {
  6.         new Student{StuNum=1, Name=”Tim”, Age=28},
  7.         new Student{StuNum=2, Name=”Ma Guo”, Age=25},
  8.         new Student{StuNum=3, Name=”Yan”, Age=25},
  9.         new Student{StuNum=4, Name=”Xaiochen”, Age=28},
  10.         new Student{StuNum=5, Name=”Miao miao”, Age=24},
  11.         new Student{StuNum=6, Name=”Ma Zhen”, Age=24}
  12.     };
  13.     this.listBox1.ItemsSource = stuList;

  14.     this.listBox1.DisplayMemberPath = “Name”;

  15.     //this.listBox1.SelectedValuePath = “StuNum”;

  16.     this.stuNumTextBox.SetBinding(TextBox.TextProperty, new Binding(“SelectedItem.StuNum”) { Source = this.listBox1 });

  17.     this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding(“SelectedItem.Name”) { Source = this.listBox1 });
  18.     this.ageTextBox.SetBinding(TextBox.TextProperty, new Binding(“SelectedItem.Age”) { Source = this.listBox1 });
  19. }

立拨,我们采取的是ListBox的SelectedItem属性——每当我们选中ListBox(包括其他ItemsControl)中之一个Item时,ListBox都见面“默默地”自动从数据源集合里选出与当下相中Item相对应的酷条目,作为协调的SelectedItem属性值。而且,上面是例子里我们以到了“多级路”——”SelectedItem.Age”,实际项目中,你可同步“点”下去,直到取出你想使的价。

乍家一般会以及时有限单地方撞题目:

  1. Q:为什么this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding(“SelectedItem.Name”) { Source = this.listBox1 });可以,而改化this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding(“Name”) { Source = this.listBox1.SelectedItem });却格外了啊?它们对的价是一样的呀!

A:第一词,Binding的Source是listBox1,这个目标在整程序中还不移,任何时候咱们且能找到它们的SelectedItem并且根据要求取出Name属性;第二句,Binding的Source是listBox1.SelectedItem,每次listBox1的挑三拣四着起改成后,listBox1.SelectedItem还见面是一个初的目标!而面就段代码是描写以构造函数里之,只在窗体构造的时实施同一不成,所以即使懵了。如果想让第二词与第一句达到平的功能,你需要将第二句写及listBox1.SelectionChanged事变之处理函数里去——这就算失去Binding的本心了。

2.
Q:为什么自己当盘算将listBox1.SelectedItem转移成ListBoxItem时,程序会丢弃来大与否?A:因为SelectedItem指的是数源集合里与界面被当选Item对应的充分目标,所以,它的花色是数据源集合的因素类型——在“数据驱动UI”的WPF中,请不要管“数据”和“界面”搅在共。

 

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

自己在惦记:有人会读到此时也?

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

 

数据的“制高点”——DataContext

所去8年,那时候哥们儿还混入于有农业院校……在反恐流行起来之前,我们几乎单兄弟最喜爱恶作剧的是《三角洲部队》。有同样种植游戏模式让“抢山头”,也尽管是夺取制高点啦!制高点意味着什么?它象征站于下面的丁犹好望见站在面的总人口,而且若其他一个总人口高达来了,就见面把前面一个挤下。

今日咱们设讨论滴不是戏,挣钱要紧,学习WPF先。WPF也也咱准备了一个为此来放置数的“制高点”——DataContext。

怎知道这数目制高点呢?让咱们就看上面的先后。现在客户的需要又转换了:要求于窗体里亮两独ListBox,一个内显示学生列表,一个中显示老师列表,选中任何一个ListBox里的项,下面的TextBox都亮相应的详细信息。

这儿我们遇到困难了!因为一个UI元素不容许binding到片只数据源上啊!怎么处置为?这时候DataContext就派上用场了。

 

先是我们拿界面改成为这样:

 

  1. <Window x:Class=”CollectionBinding.Window1″

  2.     xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

  3.     xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

  4.     Title=”水的真谛” Height=”300″ Width=”300″>

  5.     <StackPanel>
  6.         <ListBox Name=”stuListBox” Margin=”5″ Height=”70″ Background=”LightBlue”/>

  7.         <ListBox Name=”tchrListBox” Margin=”5″ Height=”70″ Background=”LightPink”/>

  8.         <TextBox Name=”idTextBox”  Margin=”5″ Background=”LightGreen”/>

  9.         <TextBox Name=”nameTextBox”  Margin=”5″ Background=”LightGreen”/>

  10.         <TextBox Name=”ageTextBox”  Margin=”5″ Background=”LightGreen”/>

  11.     </StackPanel>

  12. </Window>

效果图:

 

C++ 11

 

对应地,我们重构了一晃Student类和Teacher类,让她趋于一致:

 

  1. interface ISchoolMember
  2. {
  3.      int ID { get; set; }
  4.      string Name { get; set; }

  5.      int Age { get; set; }

  6. }

  7. class Student : ISchoolMember
  8. {
  9.     public int ID { get; set; }
  10.     public string Name { get; set; }
  11.     public int Age { get; set; }
  12. }
  13. class Teacher : ISchoolMember
  14. {
  15.     public int ID { get; set; }
  16.     public string Name { get; set; }
  17.     public int Age { get; set; }
  18. }

现行为我们看DataContext是怎么耍的:

 

  1. public Window1()
  2. {
  3.     InitializeComponent();
  4.     List<Student> stuList = new List<Student>() 
  5.     {
  6.         new Student{ID=1, Name=”Tim”, Age=28},
  7.         new Student{ID=2, Name=”Ma Guo”, Age=25},
  8.         new Student{ID=3, Name=”Yan”, Age=25},
  9.     };
  10.     List<Teacher> tchrList = new List<Teacher>()
  11.     {
  12.         new Teacher{ID=1, Name=”Ma Zhen”, Age=24},
  13.         new Teacher{ID=2, Name=”Miao miao”, Age=24},
  14.         new Teacher{ID=3, Name=”Allen”, Age=26}
  15.     };
  16.     stuListBox.ItemsSource = stuList;
  17.     tchrListBox.ItemsSource = tchrList;
  18.     stuListBox.DisplayMemberPath = “Name”;

  19.     tchrListBox.DisplayMemberPath = “Name”;

  20.     stuListBox.SelectionChanged += (sender, e) => { this.DataContext = this.stuListBox.SelectedItem; };

  21.     tchrListBox.SelectionChanged += (sender, e) => { this.DataContext = this.tchrListBox.SelectedItem; };
  22.     this.idTextBox.SetBinding(TextBox.TextProperty, new Binding(“ID”));

  23.     this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding(“Name”));

  24.     this.ageTextBox.SetBinding(TextBox.TextProperty, new Binding(“Age”));

  25. }

 

C++ 12

 

于咱们来精心品尝就段代码:

 

stuListBox.SelectionChanged += (sender, e) => { this.DataContext = this.stuListBox.SelectedItem; };
tchrListBox.SelectionChanged += (sender, e) => { this.DataContext = this.tchrListBox.SelectedItem; };

随即点儿句子是片只Lambda表达式,实际上就是有限个事件处理函数的缩写——让下游程序员不用跳转就懂得少单ListBox在独家的SelectionChanged事件时有发生常犹开什么工作。我们这里做的作业就是:哪个ListBox的选取着起改成了,那就是将选中的多寡放到窗体的DataContext属性里,隐含地,就拿前面一个数据被挤走了。

 

诙谐的凡最后三词:在啊老三个TextBox设置Binding的上,我从不提供数据源——但先后一样work,为什么呢?前面我说了,DataContext是“制高点”,当一个素发现自己有Binding但以此Binding没有Source时,它就是见面“向达看”——它当会看出制高点上的多寡,这时候它会将这数量来试一尝试,有没有有Binding所指示的Path——有,就用来之所以;没有,就更向上重叠去摸索,也即是寻找更强的制高点——山外有山、天他发生天、控件外面套控件:p

 

实际项目蒙,我会根据数量的熏陶范围来选于哪一级达标安装DataContext,以及把什么目标设置也DataContext。比如:一个ListBox里的SelectedItem需要吃含有它的Grid里之别元素共享,我便可管ListBox.SelectedItem设置也Grid的DataContext,而没必要把ListBox设置为极其顶层Window的DataContext——原则就是是“范围恰恰,影响无与伦比小”。

 

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

快累吐血了~~~~

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

 

结语:

 

Binding的基本知识终于开口了了~~深呼了一口气~~希望对大家不怎么用吧!WPF目前于境内不算火,不过我想,等火起来的时,这篇稿子会使上大用场。

 

唤醒大家一点,本文中诸多C#代码(特别是同Binding相关的地方)是得活动到XAML里去的,只是为着教方便,我用C#心想事成的,实际项目被,请大家灵活掌握。

 

自身力所能及写来这几首文章来,非常感谢我的同事Anstinus,若无是外对自家读书WPF的努力支持及点,我未可能学这么快。同时还要感谢自己的前搭档——美女Yan(这家伙调到另外一个组去了)、Yan她mentor(Allen)和自身的伙伴等~~~我一旦说之是,感谢你们!文章记载的不只是技巧,还有咱们的雅——几十年以后翻开它,WPF可能早已经过时,但咱的交情将从弥新……

 

此外,Binding作为WPF的核心技术,远不止这点内容,其他重大之情还包:

  • Binding和Routed
    Event结合(常见的凡于产生数量流动时,Binding抛来一部分Routed
    Event,由外面捕捉处理) 
  • Binding与Command结合 
  • Binding以及ItemsControl的ItemTemplate/CellTemplate等DataTemplate的组合——这个很主要,甚至是每日工作的最主要内容,我会见就此专门的文章去介绍 
  • 倘若你想自己创建一个集合类,让其好与Binding配合以,别忘了它们的素一定要是兑现INotifyPropertyChanged接口,而这集自身要(或者派生自)ObservableCollection<T>……实际上无限多东西需要以实质上工作遭到失去搜寻和控制了,一两首稿子就是杯水车薪——我为无思量像琼瑶姐姐那样达到、中、下、继、再继、再还接着……