zoukankan      html  css  js  c++  java
  • WPF Binding

    让我们了解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就像一个盒子,盒子里装了一些机关用于过滤和控制数据,盒子两端各接着一根管子,管子是由管壳和管芯构成的,看上去就像下面的图:

     

    当脑子里有了这样一个形象之后,遵循下面的步骤就OK了:

    1. Source:确定哪个对象作为数据源
    2. Target:确定哪个对象作为目标
    3. Binding:声明一个Binding实例
    4. 把一根管子接到Source上并把管芯插在Source的Path上
    5. 把另一根管子接到Target上并把管芯插在Target的联动属性上

    如果有必要,可以在3与4之间设置Binding的“关卡”们。其实,第3步之后的顺序不是固定的,只是这个步骤比较好记——一概向右连接。所得结果看上去是这样:

     

    我猜你可能会问:“那个D.P.是什么呀?”

    D.P.的全称是“Dependency Property”,直译过来就是“依赖式属性”,意思是说它自己本身是没有值的,它的值是“依赖”在其它对象的属性值上、通过Binding的传递和转换而得来的。表现在例子里,它就是Target上的被数据所驱动的联动属性了!

    这里是等价的C#代码,我把它写在了Window1的构造函数里:

    [csharp] view plaincopy
     
    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. }  

    有意思的是,Source端的操作,接管子和插管芯分两步,而Target端却是在SetBinding方法中一步完成。注意啦,TextBox.TextProperty就是一个Dependency Property的庐山真面目!

    上面的代码稍有简化的余地,那就是把Path的设定转移到Binding的构造中去:

    [csharp] view plaincopy
     
    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. }  

    这样做的好处是——随便你给binding指定一个Source,只要这个Source有“Value”这个属性,binding就会自动提取它的值并传输给Target端。

    我们还可以为binding设些“关卡”:

    [csharp] view plaincopy
     
    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. }  

     还有一个小小的提示:如果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了。

     

     让我们写一个这样的类:

     

    [csharp] view plaincopy
     
    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>  

     

     接下来就是使用INotifyPropertyChanged接口“武装”这个类了,注意,这个接口在System.ComponentModel名称空间中:

     

    [csharp] view plaincopy
     
    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.     }  

     

     

    文章来源:http://blog.csdn.net/fantasiax/article/details/2577239

  • 相关阅读:
    ServU和win2003防火墙的设置
    面试题02.05 链表求和
    【每日一题】LeetCode1. 两数之和
    【每日一题】Leetcode50. Pow(x,n)
    ASP连接查询access和sqlserver的代码
    各种播放器(视频点播)代码大全 
    电脑操作最忌讳的小动作
    网络小知识
    C#、Java比较
    10年互联网十大失败案例
  • 原文地址:https://www.cnblogs.com/luohengstudy/p/3093275.html
Copyright © 2011-2022 走看看