数据绑定是一种关系,告诉WPF从源对象提取一些信息来设置目标对象的属性,这些属性始终是 依赖属性 。源对象可以是任何内容,可以是另一个元素,可以是数据对象或自己创建的数据对象。
绑定元素
<Slider Name="slider" />
<TextBlock name="textBlock" Text="Test Text" FontSize="{Binding ElementName=slider, Path=Value}"/>
数据绑定表达式使用 XAML 标记扩展(因此具有花括号)。因为要创建 System.Windows.Data.Binding 类的一个实例,所以表达式以 Binding 开头。
之所以使用 Path 而不是 Property ,因为Path可能指向属性,也可能指向索引器,也可能指向属性的属性等等。
WPF不会引发异常来表明和数据绑定相关的问题。如果指定属性或元素不存在,不会收到任何指示,只是不能在目标属性中显示数据。当调试程序时,该信息显示在 Visual Studio 的 Output 窗口中。
绑定模式
当设置 Binding.Mode 属性时,WPF允许使用 System.Windows.Data.BindingMode 枚举值中的任何一个。
枚举值 | 说明 |
---|---|
OneWay | 当源变化时更新目标属性 |
TwoWay | 当源变化时更新目标属性,并且当目标属性变化时更新源属性 |
OneTime | 最初根据源属性值设置目标属性,只生效一次 |
OneWayToSource | 与OneWay 相反,当目标变化时更新源属性 |
Default | 默认方式,有可能是双向的(TextBox.Text),也有可能是单向的 |
OneWayToSource 常用于设置非依赖属性的属性。绑定表达式只能用于设置依赖属性,但 OneWayToSource 克服这一限制,但前提是提供数值的属性本身是依赖项属性。
代码创建绑定
Binding binding = new Binding();
binding.Source = slider;
binding.Path = new PropertyPath("Value");
binding.Mode = BindingMode.TwoWay;
textBlock.SetBinding(TextBlock.FontSize, bindig);
可以通过使用 BindingOperation 类的两个静态方法移出绑定,ClearBinding() 使用依赖项属性的引用作为参数; ClearAllBindings() 使用目标元素的引用作为参数。
可以使用静态方法 BindingOperations.GetBinding() 来获取 Binding 对象,需要提供两个参数:绑定元素 和 具有绑定表达式的属性。
// binding.Path 是绑定值
// binding.Path.Path 获取绑定属性的名称
Binding binding = BindingOperations.GetBinding(textBlock, TextBlock.FontSize);
BindingExpression expression = BindingOperations.GetBindingExpression(textBlock, TextBlock.FontSize);
绑定延迟
在某些特殊情况下,使用 Delay 属性,等待一段时间之后再提交更改。
<!--用户停止输入 500毫秒后更新源对象-->
<TextBox Text="{Binding ElementName=textBlock, Path=FontSize, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged, Delay=500}" Name="textBlockFontSize"/>
绑定到非元素对象
当绑定到非元素对象时,不能使用 Binding.ElementName 属性,而是使用以下属性中的一个:
- Source : 指向源对象的引用
- RelativeSource : 这是引用,使用 RelateveSource 对象指向源对象。多用于编写控件模板以及数据模板。
- DataContext : 如果没有设置 Source 或 RelativeSource 属性,WPF就从当前元素开始在元素树上向上查找,检查每个元素的 DataContext 属性,并使用第一个非空的 DataContext 属性。
Source 属性
Source属性为了进行绑定,需要具有数据对象。可以从资源中提取数据对象,可以通过代码生成数据对象。
<!--静态对象-->
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=Source}"/>
<!--资源创建对象-->
<Window.Resources>
<FontFamily x:Key="CustomFont">Calibri</FontFamily>
</Window.Resources>
<TextBlock Text="{Binding Source={StaticResource CustomFont}, Path=Source}"/>
RelativeSource 属性
通过 RelativeSource 属性可根据相对于目标对象的关系指向源对象。RelativeSource 对象使用 FindAncestor 模式,该模式告知查找元素树直到发现 AncestorType 属性定义的元素类型。
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
FindAncestor 有4种模式:
名称 | 说明 |
---|---|
Self | 表达式绑定到同一元素的另一个属性上 |
FindAncestor | 绑定到父元素,查找元素树直至发现期望的父元素。AncestorLevel 属性略过一定数量的特定元素 |
PreviousData | 表达式绑定到数据绑定列表中的前一个数据项 |
TemplateParent | 表达式绑定到应用模板的元素。当绑定位于控件模板或数据模板内部时才能工作 |
DataContext 属性
某些情况下,会将大量元素绑定到同一个对象,使用 FrameworkElement.DataContext 属性一次性定义绑定源会更清晰,也更灵活。
当绑定表达式中省略源信息时,WPF会检查元素的 DataContext 属性,如果为 null,会继续向上在元素树中查找第一个不为null的数据上下文。如果最终没找到,绑定表达式不会为目标属性应用任何值。