如何将RelativeSource
与WPF绑定一块儿使用以及不一样的用例有哪些? html
我建立了一个库来简化WPF的绑定语法,包括更容易使用RelativeSource。 这里有些例子。 以前: canvas
{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}
后: windows
{BindTo PathToProperty} {BindTo Ancestor.typeOfAncestor.PathToProperty} {BindTo Template.PathToProperty} {BindTo #MyTextBox.Text}
如下是如何简化方法绑定的示例。 以前: ide
// 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 ui
请注意我在“BEFORE”示例中使用的方法绑定已经使用RelayCommand
优化了代码,最后我检查的不是WPF的本机部分。 没有它,'BEFORE'的例子会更长。 this
一些有用的零碎: spa
如下是如何在代码中执行此操做: code
Binding b = new Binding(); b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1); b.Path = new PropertyPath("MyElementThatNeedsBinding"); MyLabel.SetBinding(ContentProperty, b);
我很大程度上是在代码Behind中从Binding Relative Source复制了它。 orm
此外,就例子而言,MSDN页面很是好: RelativeSource Class
想象一下这个案例,咱们想要一个矩形,它的高度老是等于它的宽度,一个正方形让咱们说。 咱们可使用元素名称来完成此操做
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>
但在上面这种状况下,咱们有义务指出绑定对象的名称,即矩形。 咱们可使用RelativeSource以不一样的方式达到相同的目的
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>
对于这种状况,咱们没有义务说起绑定对象的名称,而且每当高度改变时,宽度将始终等于高度。
若是要将宽度参数设置为高度的一半,则能够经过向Binding标记扩展添加转换器来完成此操做。 咱们如今想象另外一个案例:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>
上面的状况用于将给定元素的给定属性绑定到其直接父元素之一,由于此元素包含一个名为Parent的属性。 这致使咱们进入另外一个相对源模式,即FindAncestor模式。
Bechir Bejaoui在他的文章中公开了WPF中RelativeSources的用例:
RelativeSource是一个标记扩展,当咱们尝试将对象的属性绑定到对象自己的另外一个属性时,在咱们尝试将对象的属性绑定到其相对父项的另外一个属性时,在特定绑定状况下使用在自定义控件开发的状况下将依赖项属性值绑定到一块XAML时,最后在使用一系列绑定数据的差别的状况下。 全部这些状况都表示为相对源模式。 我将逐一揭露全部这些案件。
- 模式自我:
想象一下这个案例,咱们想要一个矩形,它的高度老是等于它的宽度,一个正方形让咱们说。 咱们可使用元素名称来完成此操做
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>但在上面这种状况下,咱们有义务指出绑定对象的名称,即矩形。 咱们可使用RelativeSource以不一样的方式达到相同的目的
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>对于这种状况,咱们没有义务说起绑定对象的名称,而且每当高度改变时,宽度将始终等于高度。
若是要将宽度参数设置为高度的一半,则能够经过向Binding标记扩展添加转换器来完成此操做。 咱们如今想象另外一个案例:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>上面的状况用于将给定元素的给定属性绑定到其直接父元素之一,由于此元素包含一个名为Parent的属性。 这致使咱们进入另外一个相对源模式,即FindAncestor模式。
- 模式FindAncestor
在这种状况下,给定元素的属性将与其父元素之一Corse绑定。 与上述状况的主要区别在于,由您决定层次结构中的祖先类型和祖先等级来绑定属性。 顺便说一下,尝试使用这块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>上面的状况是两个TextBlock元素,它们嵌入在一系列边框中,而canvas元素表明它们的分层父元素。 第二个TextBlock将在相对源级别显示给定父级的名称。
所以,尝试将AncestorLevel = 2更改成AncestorLevel = 1并查看会发生什么。 而后尝试将祖先的类型从AncestorType = Border更改成AncestorType = Canvas,看看发生了什么。
显示的文本将根据Ancestor类型和级别更改。 那么若是祖先级别不适合祖先类型会发生什么? 这是一个很好的问题,我知道你将要问它。 响应是没有异常将被抛出,而且nothings将在TextBlock级别显示。
- TemplatedParent
此模式容许将给定的ControlTemplate属性绑定到应用ControlTemplate的控件的属性。 为了更好地理解这个问题,下面是一个例子
<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>若是我想将给定控件的属性应用于其控件模板,那么我可使用TemplatedParent模式。 这个标记扩展也有相似的一个,它是TemplateBinding,它是第一个的简写,但TemplateBinding在编译时以TemplatedParent的对比度进行评估,TemplatedParent在第一个运行时以后进行评估。 正如您在下图中所述,背景和内容从按钮内部应用到控件模板。
值得注意的是,对于那些对Silverlight这个想法感到磕磕绊绊的人:
Silverlight仅提供这些命令的简化子集