WPF笔记--Binding

这几天在看数据绑定,一下文字来自网络,我只记录重要的部分,个人感觉这个作者写的比较详细,废话多了点。
在学习新东西的时候,人们总是习惯拿它与自己已经了解的旧有知识去做比较,这样才掌握得快、记忆深刻。所以,经常有朋友问我:“ WPF与Windows Form最大的区别是什么?请用最简短的话告诉我。 ”OK,这个问题问的非常好——看上去WPF与WinForm最大的区别像是前面讲的那个XAML语言,但XAML只是个表层现象,WPF真正引人入胜、使之与WinForm泾渭分明的特点就是——“ 数据驱动界面 ”。围绕着这个核心,WPF准备了很多概念相当前卫的技术,其中包括为界面准备的XAML、为底层数据准备的Dependency Property和为消息传递准备的Routed Event & Command。
  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>

细心的你,一定一眼就看到只多了这样一句话:Text="{Binding ElementName=slider1, Path=Value}"

这句话的意思是说 textBox1,从此以后,你的Text属性值就与slider1这个UI元素的Value属性值关联上了,Value变的时候你的Text也要跟着变

 

非常简单是不是?请注意,这里面可蕴含了“数据驱动界面”的模型哦!在这里,我们始终把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的一个属性,完成数据的“端对端”传输。

 

在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#代码

  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. }  
上面的代码稍有简化的余地,那就是把Path的设定转移到Binding的构造中去:
  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设些“关卡”:
  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. }  

自定义数据源:

在我们项目组日常的工作中,经常需要自己写一个类,并且拿它的实例当作数据源。怎样才能让一个类成为“合格的”数据源呢?

要诀就是:

  1.  为这个类定义一些Property,相当于为Binding提供Path
  2. 让这个类实现INotifyPropertyChanged接口。实现这个接口的目的是当Source的属性值改变后通知Binding(不然人家怎么知道源头的数据变了并进行联动协同呢?),好让Binding把数据传输给Target——本质上还是使用事件机制来做,只是掩盖在底层、不用程序员去写event handler了。

 让我们写一个这样的类:

 

  1. 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. }  
接下来就是使用INotifyPropertyChanged接口“武装”这个类了,注意,这个接口在System.ComponentModel名称空间中:
  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.     }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值