我如何使用WPF绑定的RelativeSource,有哪些不同的用例?
当前回答
这是我在空数据网格上使用该模式的一个示例。
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="Background">
<Setter.Value>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
其他回答
如果你想绑定到对象上的另一个属性:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
如果你想获取一个祖先的属性:
{Binding Path=PathToProperty,
RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
如果你想在父模板上获得一个属性(所以你可以在一个ControlTemplate中做2种方式绑定)
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
或者更短(这只适用于OneWay绑定):
{TemplateBinding Path=PathToProperty}
我刚刚发布了另一个在Silverlight中访问父元素的DataContext的解决方案。它使用Binding ElementName。
Bechir Bejaoui在他的文章中揭露了WPF中RelativeSources的用例:
The RelativeSource is a markup extension that is used in particular binding cases when we try to bind a property of a given object to another property of the object itself, when we try to bind a property of a object to another one of its relative parents, when binding a dependency property value to a piece of XAML in case of custom control development and finally in case of using a differential of a series of a bound data. All of those situations are expressed as relative source modes. I will expose all of those cases one by one. Mode Self: Imagine this case, a rectangle that we want that its height is always equal to its width, a square let's say. We can do this using the element name <Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/> But in this above case we are obliged to indicate the name of the binding object, namely the rectangle. We can reach the same purpose differently using the RelativeSource <Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/> For that case we are not obliged to mention the name of the binding object and the Width will be always equal to the Height whenever the height is changed. If you want to parameter the Width to be the half of the height then you can do this by adding a converter to the Binding markup extension. Let's imagine another case now: <TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/> The above case is used to tie a given property of a given element to one of its direct parent ones as this element holds a property that is called Parent. This leads us to another relative source mode which is the FindAncestor one. Mode FindAncestor In this case, a property of a given element will be tied to one of its parents, Of Corse. The main difference with the above case is the fact that, it's up to you to determine the ancestor type and the ancestor rank in the hierarchy to tie the property. By the way try to play with this piece of XAML <Canvas Name="Parent0"> <Border Name="Parent1" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent2"> <Border Name="Parent3" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent4"> <TextBlock FontSize="16" Margin="5" Text="Display the name of the ancestor"/> <TextBlock FontSize="16" Margin="50" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}, AncestorLevel=2},Path=Name}" Width="200"/> </Canvas> </Border> </Canvas> </Border> </Canvas> The above situation is of two TextBlock elements those are embedded within a series of borders and canvas elements those represent their hierarchical parents. The second TextBlock will display the name of the given parent at the relative source level. So try to change AncestorLevel=2 to AncestorLevel=1 and see what happens. Then try to change the type of the ancestor from AncestorType=Border to AncestorType=Canvas and see what's happens. The displayed text will change according to the Ancestor type and level. Then what's happen if the ancestor level is not suitable to the ancestor type? This is a good question, I know that you're about to ask it. The response is no exceptions will be thrown and nothings will be displayed at the TextBlock level. TemplatedParent This mode enables tie a given ControlTemplate property to a property of the control that the ControlTemplate is applied to. To well understand the issue here is an example bellow <Window.Resources> <ControlTemplate x:Key="template"> <Canvas> <Canvas.RenderTransform> <RotateTransform Angle="20"/> </Canvas.RenderTransform> <Ellipse Height="100" Width="150" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"> </Ellipse> <ContentPresenter Margin="35" Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"/> </Canvas> </ControlTemplate> </Window.Resources> <Canvas Name="Parent0"> <Button Margin="50" Template="{StaticResource template}" Height="0" Canvas.Left="0" Canvas.Top="0" Width="0"> <TextBlock FontSize="22">Click me</TextBlock> </Button> </Canvas> If I want to apply the properties of a given control to its control template then I can use the TemplatedParent mode. There is also a similar one to this markup extension which is the TemplateBinding which is a kind of short hand of the first one, but the TemplateBinding is evaluated at compile time at the contrast of the TemplatedParent which is evaluated just after the first run time. As you can remark in the bellow figure, the background and the content are applied from within the button to the control template.
在WPF中,RelativeSource绑定公开了三个属性来设置:
1. Mode:这是一个枚举,可以有四个值:
a. PreviousData(value=0):它将属性的上一个值赋给 约束函数 b. TemplatedParent(value=1):在定义的模板时使用 任何控件,并希望绑定到控件的值/属性。 例如,定义ControlTemplate:
<ControlTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</ControlTemplate>
c. Self(value=2):当我们想从一个Self或Self的属性绑定时。 例如:在设置复选框上的命令时,将复选框的选中状态发送为CommandParameter
<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />
d. FindAncestor(value=3):当想从父控件绑定时 在可视化树中。 例如:在记录中绑定一个复选框,如果选中了网格,如果选中了标题复选框
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />
2. 祖宗类型:当模式是find祖宗,然后定义什么类型的祖先
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}
3.祖宗级别:当模式是FindAncestor时,那么祖先的级别是什么(如果在可视树中有两个相同类型的父)
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}
以上是RelativeSource绑定的所有用例。
这里有一个参考链接。
我创建了一个库来简化WPF的绑定语法,包括让它更容易使用RelativeSource。这里有一些例子。之前:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
{Binding Path=Text, ElementName=MyTextBox}
后:
{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}
下面是一个如何简化方法绑定的示例。之前:
// C# code
private ICommand _saveCommand;
public ICommand SaveCommand {
get {
if (_saveCommand == null) {
_saveCommand = new RelayCommand(x => this.SaveObject());
}
return _saveCommand;
}
}
private void SaveObject() {
// do something
}
// XAML
{Binding Path=SaveCommand}
后:
// C# code
private void SaveObject() {
// do something
}
// XAML
{BindTo SaveObject()}
你可以在这里找到图书馆:http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
请注意,在我用于方法绑定的“BEFORE”示例中,代码已经通过使用RelayCommand进行了优化,我最后检查它不是WPF的本机部分。没有这个BEFORE的例子会更长。
推荐文章
- 按类型查找WPF窗口中的所有控件
- 数组与列表的性能
- 从Description属性中获取Enum
- 为什么使用try {} finally{}和一个空的try块?
- 如何在内存中获取对象大小?
- 每个优秀的。net开发人员都应该能够回答的问题?
- 如何编辑。csproj文件
- EscapeUriString和EscapeDataString的区别是什么?
- 在c++ /CLI中插入号(' ^ ')是什么意思?
- 什么时候应该使用TaskCompletionSource<T> ?
- 为什么处理排序数组比未排序数组慢?
- .net中ObservableCollection有什么用?
- LINQ单对第一
- 如何获得具有给定属性的属性列表?
- 例外。Message vs . Exception.ToString()