Binding的源和路径
- Binding的源
Binding的源也就是数据的源头。Binding对源的要求并不苛刻---只要它是一个对象,并且通过属性(Property)公开自己的数据,它就能作为Binding的源。
实体类作为Binding的源,需要实现INotifyPropertyChanged接口并在属性set中触发PropertyChanged事件。详细内容可见http://www.cnblogs.com/yijiaoyingbi/p/4841038.html
为了让UI元素产生一些联动效果,可以使用Binding在控件间建立关联。如下代码所示,把一个TextBox的Text属性关联在了Slider的Value属性上。
<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="150" Width="225"> <StackPanel Margin="0,0,0,-1"> <TextBox x:Name="textBox1" Text="{Binding Path=Value,ElementName=slider1}" BorderBrush="Black" Margin="5"></TextBox> <Slider x:Name="slider1" Maximum="100" Minimum="0" Margin="5"></Slider> </StackPanel> </Window>
Text="{Binding Path=Value,ElementName=slider1}" 使用了Binding的标记扩展语法,与之等价的C#代码是:
this.textBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1" });
- Binding数据更新
运行上面的例子,可以发现,拖动Slider之后,TextBox的Text会发生变化,当手动在TextBox输入一个数值然后按下Tab使TextBox失去焦点后,Slider的值也会发生变化,这就涉及到了Binding的两个属性Mode和UpdateSourceTrigger。
Binding在源与目标之间架起了沟通的桥梁,默认情况下数据既能够通过Binding送达目标,也能够从目标返回源(收集用户对数据的修改)。有的时候数据只是需要展示给用户、不允许用户修改,这就可以把Binding模式修改为源向目标的单向沟通。控制Binding数据流向的属性就是Mode,它的类型是BindingMode枚举。
为什么TextBox失去焦点后Slider的Value才会发生改变呢?这涉及到了Binding的另一个属性---UpdateSourceTrigger,它的类型是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFocus、Explicit和Default。
- Binding的路径
Bindig的路径指明Binding关注的是源的哪个属性。尽管在XAML代码中或者Binding的构造函数的参数列表中我们以一个字符串表示Path,但Path的实际类型是PropertyPath。以上面例子中指定Path的代码为例Path=Value,与之等效的C#代码是:
Binding binding = new Binding() { Path = new PropertyPath("Value"), Source = this.slider1 }; this.textBox1.SetBinding(TextBox.TextProperty, binding);
Binding还支持多级路径,通俗讲就是一路“点”下去。比如我们想让一个TextBox显示另一个TextBox的文本长度,我们可以这样写:
<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="150" Width="225" Loaded="Window_Loaded"> <StackPanel Margin="0,0,0,-1"> <TextBox x:Name="textBox1" Text="" BorderBrush="Black" Margin="5"></TextBox> <TextBox x:Name="textBox2" Text="{Binding Path=Text.Length,ElementName=textBox1,Mode=OneWay}" BorderBrush="Black" Margin="5"/> </StackPanel> </Window>
我们知道,集合类型的索引器(Index)又被称为带参属性。既然是属性,索引器也能作为Path来使用。比如我们想让一个TextBox显示另一个TextBox问的第四个字符就可以这样写:
<TextBox x:Name="textBox2" Text="{Binding Path=Text[3],ElementName=textBox1,Mode=OneWay}" BorderBrush="Black" Margin="5"/>
当使用一个集合或DataView作为Binding的源时,如果我们想把它的默认元素当作Path使用,则需要使用这样的语法:
List<string> stringList = new List<string>() { "Hello", "World", "WPF" }; this.textBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList }); this.textBox2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList,Mode=BindingMode.OneWay }); this.textBox3.SetBinding(TextBox.TextProperty, new Binding("/[1]") { Source = stringList,Mode=BindingMode.OneWay });
如果集合元素的属性仍然是一个集合,我们想把子级集合中的元素当作Path,则可以使用多级斜线的语法。
有的时候,我们会在代码中看到一些Path是一个“.”或者干脆没有Path的Binding,其实这是一种比较特殊的情况,即Binding的源本身就是数据且不需要Path来指明。典型的String、int等基本数据类型,它们本身就是数据,我们无法指出通过它的哪个属性来访问这个数据。在XAML里这个“.”可以省略,但在C#代码里不能省略。