将元素绑定到一起
数据绑定的最简单情形是,源对象是WPF元素而且源属性是依赖属性。
绑定表达式
数据绑定表达式使用XMAL标记扩展(因此具有花括号)。因为正在创建System.Windows.DataBinding
类的一个实例,所以绑定表达式以单词Binding
开头。尽管可采用多种方式破诶只Binding对象,但本示例只需要设置两个属性:ElementName
属性(指示源元素)和Path属性(指示源元素中的属性)
1 | <StackPanel> |
之所以使用名称Path而不是Property,是因为Path可能指向属性的属性(如FontFamily.Source),也可能只想属性使用的索引器(如Content.Children[0])。可构建具有多级层次的路径,使其指向属性的属性的属性,依此类推。
绑定错误
WPF 不会引发异常来通知与数据绑定相关的问题。如果指定的元素或属性不存在,那么不会收到任何指示;相反,只是不能在目标属性中显示数据。
乍一看,对调试而言这像是可怕的梦魇。幸运的是,WPF输出了绑定失败细节的跟踪信息。当调试应用程序时,该信息显示在 VisuaStudio 的 Output 窗口中。
绑定模式
数据绑定的一个特性是目标会被自动更新,而不考虑源的修改方式。
名称 | 说明 |
---|---|
OneWay | 当源属性变化时更新目标属性 |
TwoWay | 当源属性变化时更新目标属性,并且当目标属性变化时更新源属性 |
OneTime | 最初根据源属性值设置目标属性。然而,其后的所有改变都会被忽略(除非绑定被设置为一个完全不同的对象或者调用 BindingExpression.UpdateTarget()方法,正如稍后介绍的那样)。通常,如果知道源属性不会变化,可使用这种模式降低开销 |
OneWayToSource | 与OnWay 类型类似,但方向相反。当目标属性变化时更新源属性(这看起来有点像向后传递),但目标属性永远不会被更新 |
Default | 此类绑定依赖于目标属性。既可以是双向的(对于用户可以设置的属性,如TextBox.Text属性),也可以是单向的(对于所有其他属性)。除非明确指定了另一种模式,否则所有绑定都使用该方法 |
使用代码创建绑定
在构建窗口时,在XAML标记中使用Binding标记扩展来声明绑定表达式通常最高效。然而,也可使用代码创建绑定
1 | public MainWindow() |
1 | <StackPanel> |
使用代码检索绑定
可使用代码检索绑定并检查其属性,而不必考虑绑定最初是用代码还是标记创建的。
通过GetBinding
1 | Binding binding = BindingOperations.GetBinding(simpleText,TextBlock.FontSizeProperty); |
通过GetBindingExpression
1 | BindingExpression expression = BindingOperations.GetBindingExpression(simpleText,TextBlock.FontSizeProperty); |
多绑定
1 | <StackPanel> |
绑定更新
绑定更新的触发时机由Binding.UpdateSourceTrigger
属性控制。
名称 | 说明 |
---|---|
PropertyChanged | 当目标属性发生变化时立即更新源 |
LostFocus | 当目标属性发生变化并且目标失去焦点时更新源 |
Explicit | 除非调用BindingExpression.UpdateSource() 方法,否则无法更新源 |
Default | 根据目标属性的元数据确定更新行为(从技术角度看,是根据FrameworkPropertyMetadataDefaultUpdateSourceTriggcr属性决定更新行为)。大多数属性的默认行为是PropertyChanged但 TextBox.Text属性的默认行为是 LostFocus |
1 | <TextBox x:Name="textBox" |
TextBox.Text属性的默认行为是LostFocus,这仅是因为当用户输入内容时,文本框中的文本会不断地变化,从而会引起多次更新。根据源控件更新自身的方式,PropertyChanged 更新模式会使应用程序的运行更缓慢。此外,可能会导致源对象在编辑完成之前重新更新自身,而这可能引起验证问题。
延迟绑定
在极少数情况下,需要防止数据绑定触发操作和修改源对象,至少在某一时段是这样的。例如,可能想在从文本框复制信息之前暂停,而不是在每次按键后获取。或者,源对象在数据绑定属性变化时执行处理器密集型操作。在此情况下,可能要添加短暂的延迟时间,避免过分频繁地触发操作。
在这些特殊情况下,可使用 Binding对象的 Delay 属性。等待数毫秒,之后再提交更改。下面是文本框示例的修改版本,会在用户停止输入500 毫秒(半秒钟)后更新源对象:
1 | <TextBox x:Name="textBox" |
绑定到非元素对象
当绑定到非元素对象时,需要放弃Binding ElementName
属性,并使用以下属性中的一个:
- Source :甘肃新时指向源对象的引用——换句话说,时提供数据的对象
- RelativeSource :这是引用,使用RelateveSource对象指向源对象。有了这个附加层,可在当前元素(包含绑定表达式的元素)的基础上构建引用。这似乎无谓地增加了复杂程度,但实际上,RelativeSource属性是一种特殊工具,当编写控件模板以及数据模板时是很方便的。
- DataContext:如果没有使用Source或RelativeSource属性指定源,WPF 就从当前元素开始在元素树中向上查找。检查每个元素的DataContext属性,并使用第一个非空的DataContext属性。当我要将同一个对象的多个属性绑定到不同的元素时,DataContext属性是非常有用的,因为可在更高层次的容器对象上(而不是直接在目标元素上)设置DataContext 属性。
Source属性
最简单的选择时将SOurce属性指向一些已经准备好了的静态对象。
1 | <TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=Source}"/> |
另一种选择是绑定到先前作为资源创建的对象。例如,下面的标记创建指向Calibri字体的FontFamily 对象:
1 | <Window.Resources> |
RelativeSource属性
通过 RelativeSource 属性可根据相对于目标对象的关系指向源对象。例如,可使用RelativeSource 属性将元素绑定到自身或其父元素(不知道在元素树中从当前元素到绑定的父元素之间有多少代)。
为设置 Binding.RelativeSource 属性,需要使用 RelativeSource 对象。这会使语法变得更加复杂,因为除了需要创建 Binding对象外,还需要在其中创建嵌套的 RelativeSource 对象。一种选择是使用属性设置语法而不是使用 Binding 标记扩展。例如,下面的代码为 TextBlock.Text属性创建了一个 Binding 对象,这个 Binding 对象使用査找父窗口并显示窗口标题的 RelativeSource对象:
1 | <TextBlock> |
编写绑定更常用的方法是使用 Binding和 RelativeSource 标记扩展,将其合并到一个字符串:
1 | <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" /> |
名称 | 说明 |
---|---|
Self | 表达式绑定到同一个元素 的另一个属性上 |
FindAncestor | 表达式绑定到父元素。WPF 将查找元素树直至发现期望的父元素。为了指定父元素,还必须设置 AncestorType 属性以指示希望査找的父元素的类型。此外,还可以用AncestorLevel属性略过发现的一定数量的特定元素 。例如,当在一棵树中查找时,如果希望绑定到第三个ListBoxltem 类型的元素,应当使用如下设置–AncestorType-{x:Type ListBoxltem};并且 AncestorLevel=3,从而略过前两个ListBoxItem元索。默认情况下,AncestorLevel 属性设置为1,并在找到第一个匹配的元素时停止查找 |
PreviousData | 表达式绑定到数据绑定列表中的前一个数据项。在列表项中会使用这种模式 |
TeampleParent | 表达式绑定到应用模板的元素。只有当绑定位于控件模板或数据模板内部时,这种模式才能工作 |
DataContext属性
在某些情况下,会将大量元素绑定到同一个对象。例如,下面的一组TextBlock元素,需要为每一个元素绑定表达式显得很臃肿,因此可以给父元素绑定DataContext
属性
1 | <StackPanel> |
1 | <StackPanel DataContext="{x:Static SystemFonts.IconFontFamily}"> |
如果使用Source属性创建明确标识源的绑定,元素就会使用源而不会使用可能得到的任何数据上下文