绑定到非元素对象
当绑定到非元素对象时,需要放弃Binding.ElementName属性,并使用以下属性中的一个:
– Source:该属性是指向源对象的引用——换句话说,是提供数据的对象
– RelativeSource:使用RelativeSource对象指向源对象。有了这个附加层,可在当前元素(包含绑定表达式的元素)的基础上构建引用。在编写空间模板以及数据模板时是很方便的。
– DataContext:如果没有使用Source或或RelativeSource属性指定源,WPF就从当前元素开始在元素数中向上查找。检查没个元素的DataContext属性,并使用第一个非空的DataContext属性。当我要将同一个对象的多个属性绑定到不同的元素时,DataContext属性是非常有用的,因为可在更高层次的容器对象上(而不是直接在目标元素)设置DataContext属性。
Source属性
唯一的问题是为了进行绑定,需要具有数据对象。可以从资源中提取数据对象,可通过编写代码生成数据对象。
1. 最简单的选择是将Source属性指向一些已经准备好的静态对象,
例如:
<TextBlock Text="{Binding source={x:static SystemFonts.IconFontFamily},Path=Source}"></TextBlock>
这个绑定表达式获取由静态属性SystemFonts.IconFontFamily提供的FontFamily对象(注意,为了设置Binding.Source属性,需要借助静态标记扩展)。然后,将Binding.Path属性设置为FontFamily.Source属性,该属性给出了字体家族的名字。
2. 另一种选择是绑定到先前作为资源创建的对象
<Window.Resources>
<FontFamily x:Key="CustomFont">Calibri</FontFamily>
</Window.Resources>
并且下面的TextBlock元素会被绑定到该资源:
<TextBlock Text="{Binding Source={staticResource CustomFont},Path=Source}"></TextBlock>
RelativSource属性
通过RelativeSource属性可根据相对于目标对象的关系指向源对象,例如可以使用RelativeSource属性将元素绑定到自身或其其复元素(不知道在元素树种从当前元素到绑定的父元素之间有多少代)
为设置Binding.RelativeSource属性,需要使用RelativeSource对象。这会使语法更加复杂,因为除了需要创Binding对象外,还需要在其中创建嵌套的RelativeSource对象,一种选择是使用属性设置语法而不是使用Binding标记扩展。
<TextBlock>
<TextBlock.Text>
<Binding Path="Title">
<Binding.RelativeSource>
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}"/>
</Binding.RelativeSource>
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
RelativeSource对象使用FindAncestor模式,搞模式告知查找元素树直到发现AncestorType属性定义的元素类型。
可以写为
<TextBlock Text="{Binding Path=Title,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}}"></TextBlock>
FindAncestor模式有四种
名称 | 说明 |
---|---|
Self | 表达式绑定到同一元素的另一个属性上 |
FindAncestor | 表达式绑定到父元素。WPF将查找元素树直至发现期望的父元素。为了指定父元素,还必须设置AncestorType属性以指示希望查找的父元素的类型,此外还可以用AncesotrLevel属性略过发现的一定是胡亮的特定元素 |
PreviousData | 表达式绑定到数据绑定列表中的前一个数据项。在列表项中会使用这种模式 |
TemplateParent | 表达式绑定到应用模板的元素。只有当绑定位于控件模板或数据模板内部时,这种模式才能工作 |
DataContext属性
在某些情况下,会将大量元素绑定到同一个对象。例如,分析下面一组TexBlock元素,每个TextBlock元素都使用类似的绑定表达式提取与默认图标字体相关的不同细节,包括行间距,以及每一个字体的样式和粗细。可以为每个TextBlock元素使用Source属性,但这样会使标记变得非常长。
对于这种情况,使用FrameworkElement.DataContext属性一次性定义绑定源会更清晰,也更灵活。
<StackPanel DataContext="{x:Static SystemFonts.IconFontFamily}">
<TextBlock Margin="5" Text="{Binding Path=Source}"></TextBlock>
</StackPanel>
WPF会检查元素的DataContext属性。如果属性值为Null,WPF会继续向上在元素树种查找第一个不为null的数据上下文(最初,所有元素的DataContext属性都是null)。如果找到了一个数据上下文,就为绑定使用找到的数据上下文。如果没有找到,绑定表达式不会为目标属性应用任何值。