简单来说,数据绑定是一种关系,最简单的关系就是 源对象是WPF元素而且源属性是依赖项属性
绑定表达式
当使用数据绑定时,不必对源对象(如Slider控件)做任何改动,只需要配置源对象使其属性具有正确的值范围
<Slider Name="SliderFontSize" Margin="3" Minimum="1" Maximum="40" Value="10" TickFrequency="1" TickPlacement="TopLeft"> </Slider> <TextBlock Margin="10,38,10,-18" Text="Simple Text" Name="lblSampleText" FontSize="{Binding ElementName=SliderFontSize,Path=Value}"> </TextBlock>
数据绑定表达式使用XAML标记扩展,以单词Binding开头,以上的代码设置了两个属性:ElementName属性(指示源元素)和Path属性(源元素中的属性)
之所以使用名称Path,是因为Path可能指向属性的属性(FontFamily.Source)也可能是指向属性使用的索引器(Content.Children[0])。可构建具有多层次的路径,使其指向属性的属性的属性。
绑定错误
WPF不会引发异常,但会出现类似于:
绑定模式
单击Set to Large按钮时,会运行下面的代码
private void Button_Click(object sender, RoutedEventArgs e){
SliderFontSize.Value = 30;
}
效果会通过数据绑定强制改变字体尺寸。效果与移动滑动条上的滑块一样
而下面的代码却无法达到正常的效果,破坏了绑定,滑块无法对字体做出改变。
private void Button_Click(object sender, RoutedEventArgs e){
lblSampleText.FontSize = 30;
}
可以使用一种方式,强制在两个方向传递数值:从源到目标以及从目标到源。
<TextBlock Margin="40" Text="Simple Text" Name="lblSampleText" Width="300" Height="100" FontSize="{Binding ElementName=SliderFontSize,Path=Value,Mode=TwoWay}">
目前还不要考虑使用双向绑定。
但设置Binding.Mode属性时,WPF有5个
对于几种模式,如下图
OneWayToSource
和OneWay的区别,是绑定表达式的放置位置
OneWayToSource模式允许通过在通常被视为绑定源的对象中放置表达式,从而翻转源和目标。
使用这个方式常见的原因是设置非依赖项模式(绑定表达式只能用于依赖项模式),但通过这个模式可以克服这个箱子,但前提是提供数值的属性本身是依赖项属性
Default
WPF使用了一种不同的,默认情况下依赖于所绑定属性的模式(每一个依赖项属性都有一个元数据 FrameworkPropertyMetadata.BindsTwoWayByDefault标志,该标志指示属性是使用单项绑定还是双向绑定)
使用代码创建绑定
还可以使用BindingOperation类的两个静态方法移除绑定。ClearBinding()方法使用依赖项属性(该属性具有希望删除的绑定)的引用作为参数。而ClearAllBindins()方法为元素删除所有数据绑定
在一些特殊的情况下,会希望使用代码创建绑定
使用代码检索绑定
可使用代码检索绑定并检查其属性,而不必考虑绑定最初是用代码还是标记创建的
可采用两种方式来获取绑定信息。第一种方式是使用静态方法BindingOperations.GetBinding来检索相应的Binding对象。这需要提供两个参数:绑定元素以及具有绑定表达式的属性
一旦拥有绑定对象,就可以检查其属性。绑定元素名Binding.ElementName提供了表达式的值(这里是sliderFontSize),Binding.Path提供了PropertyPath对象从绑定对象提取绑定值,Binding.Path.Path获取绑定属性的名称(这里是Value)。还有Binding.Mode属性,用于告知绑定何时更新元素。
WPF还允许通过调用BindingOperations.GetBingingExpression方法获得更实用的BindingExpression对象。
BindingExpression对象包括一些属性,用于复制Bingding对象提供的信息。
多绑定
希望目标属性受多个源的影响,比如,如果希望使用两个相等的合法绑定来设置属性(创建绑定时,只能指定一个目标属性),可使用多种方法突破这一限制。
最简单的方法是更改数据绑定模式,Mode属性允许改变绑定方向,(双向绑定),可使用这项技术创建多个设置同一属性的绑定表达式。
对滑动条实例的一个变体,添加一个能设置精确字体尺寸的文本框。可以使用文本框和滑块设置字体。
尽管不能再为FontSize属性添加另外一个绑定,但可以将新控件TextBox绑定到TextBlock.FontSize属性
<TextBox HorizontalAlignment="Left" Height="23" Margin="240,304,0,0" TextWrapping="Wrap" Text="{Binding ElementName=lblSampleText,Path=FontSize,Mode=TwoWay}" VerticalAlignment="Top" Width="120" />
Slider.Value属性是双精度类型,将TickFrequency属性设置为1,将IsSnapToTick属性设置为true
直到文本框失去焦点,才会应用文本框中的改变。如果不希望这么做,可以使用Bindind对象的UpdateSourceTrigger属性立即更新
注意,如果使用textbox去绑定滑块,则是立即更新
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Slider Name="SliderFontSize" Margin="3" Minimum="1" Maximum="40" Value="{Binding ElementName=txt,Path=Text}" TickFrequency="1" TickPlacement="TopLeft"> </Slider> <TextBlock Margin="40" Text="Simple Text" Name="lblSampleText" Width="300" Height="100" FontSize="{Binding ElementName=SliderFontSize,Path=Value,Mode=TwoWay}"> </TextBlock> <Button Content="Set to Large" HorizontalAlignment="Left" Margin="608,279,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/> <TextBox HorizontalAlignment="Left" Height="23" Margin="240,304,0,0" TextWrapping="Wrap" Text="10" VerticalAlignment="Top" Width="120" x:Name="txt"/> </Grid> </Window>
绑定更新
为什么以上两种绑定更新的时间不同?
当使用OneWay或TwoWay绑定时,改变后的值会立即从源传播到目标。当反向传递时,从目标到源,未必会立即发送。
它们的行为Binding.UpdateSourceTrigger属性控制,
<TextBox HorizontalAlignment="Left" Height="23" Margin="240,304,0,0" TextWrapping="Wrap" Text="{Binding ElementName=lblSampleText,Path=FontSize,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120" />
要完全控制对象的更新时机,可选择Explicit模式,此时由你的代码手动更新。
可添加Apply按钮,调用BindingExpression.UpdateSouce方法,触发立即刷新行为
当然在使用BindingExpression之前,我们需要一个类来获取。
BindingExpression对象包括:
为了获取BindingExpression对象,需要使用GetBindingExpression方法,并传入具有绑定的目标属性
绑定延迟
可以使用Binding对象的Delay属性
绑定到非元素对象
当绑定到非元素对象时,需要放弃Binding.ElementName属性,并使用以下属性中的一个:
Source属性
source为了数据绑定,需要具有数据对象。
可使用几种方法获取数据对象。可从资源中提取数据对象,可通过编写代码生成数据对象,也可在数据提供的程序的帮助下获取数据对象。
这个绑定表达式获取由静态属性SystemFonts.IconFontFamily提供的FontFamily对象,然后将Binding.Path属性设置为FontFamily.Source属性。
RelativeSource
通过RelativeSource属性可根据相对于目标对象的关系指向源对象。可使用RelativeSource属性将元素绑定到自身或父元素
为设置Bind.RelativeSource属性,需要使用RelativeSource对象,这样需要多创建一个RelativeSource对象。
<TextBlock> <TextBlock.Text> <Binding Path="Title"> <Binding.RelativeSource> <RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}"> </RelativeSource> </Binding.RelativeSource> </Binding> </TextBlock.Text> </TextBlock>
FindAncestor模式。告知查找元素树知道发现AncestorType属性定义的元素模式
更常用的方法是使用Binding和RelativeSource标记扩展
<TextBlock Text="{Binding Path=Title,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}}"></TextBlock>
并不总是可以使用Source或ElementNmae,因为源对象和目标对象在不同的标记块中。
DataContext属性
在某些情况下,会将大量的元素绑定到同一个对象。
可以在StackPanel里面设置绑定
当绑定表达式中省略信息时,WPF会检查元素的DataContext属性。如果属性为null,WPF会继续向上查找不为null的数据上下文。如果找到了一个数据上下文,就为绑定使用找到的数据上下文,没有找到就不设置。