.net - 我如何使用WPF绑定与RelativeSource?




xaml data-binding (10)

Bechir Bejaoui在他的文章中公开了WPF中RelativeSources的用例:

RelativeSource是一种标记扩展,当我们尝试将给定对象的属性绑定到对象本身的另一个属性时,在我们试图将对象的属性绑定到其相对父对象的另一个时,在自定义控件开发的情况下将依赖项属性值绑定到一段XAML,最后在使用一系列绑定数据的差异的情况下。 所有这些情况都表示为相对来源模式。 我将逐一公开所有这些案例。

  1. 模式自我:

想象一下,这种情况下,我们想要一个矩形,它的高度总是等于它的宽度,让我们假设一个正方形。 我们可以使用元素名称来做到这一点

<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}"/>

对于这种情况,我们没有义务提及绑定对象的名称,并且每当高度发生变化时,宽度将始终等于高度。

如果您想将宽度参数设置为高度的一半,则可以通过向绑定标记扩展添加转换器来完成此操作。 现在让我们来想象另一个案例:

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
               Path=Parent.ActualWidth}"/>

上述情况用于将给定元素的给定属性与其直接父元素的给定属性绑定在一起,因为此元素拥有一个名为Parent的属性。 这导致我们到另一个相对来源模式,即FindAncestor。

  1. 模式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元素,以及那些表示其父层次结构的画布元素。 第二个TextBlock将在相对源级别显示给定父级的名称。

所以尝试将AncestorLevel = 2更改为AncestorLevel = 1,看看会发生什么。 然后尝试将AncestorType = Border的祖先类型更改为AncestorType = Canvas,看看会发生什么。

显示的文字将根据祖先的类型和等级而改变。 那么,如果祖先级别不适合祖先类型,会发生什么? 这是一个很好的问题,我知道你会问这个问题。 响应是没有例外的将被抛出,并且将在TextBlock级别显示不会出现的异常。

  1. 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是在第一次运行时间之后进行评估的。 正如您可以在下图中所说的那样,背景和内容从按钮内部应用到控件模板。

我如何使用WPF绑定的RelativeSource以及哪些不同的用例?


WPF RelativeSource绑定中公开了3个properties来设置:

1.模式:这是一个可能有四个值的enum

一个。 PreviousData( value=0 ):它将property的前一个值分配给绑定的property

TemplatedParent( value=1 ):这用于定义任何控件的templates并且要绑定到控件的value / Property。

防爆。 定义ControlTemplate

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>

C。 自我( value=2 ):当想要从selfselfproperty绑定。

防爆。CheckBox上设置Command时,将checkbox选中状态作为CommandParameter发送

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />

d。 FindAncestor( value=3 ):想要从Visual Tree的父control进行绑定时。

防爆。 如果checkboxgrid ,如果checkbox header checkbox ,则在records绑定checkbox

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type iDP:XamDataGrid}},Path=DataContext.IsHeaderChecked,Mode=TwoWay}" />

2. AncestorType:当模式是FindAncestor然后定义祖先的类型

RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type iDP:XamDataGrid}}

3.AncestorLevel 当模式是FindAncestor那么什么级别的ansector(如果在visual tree有两个相同类型的父级)

RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type iDP:XamDataGrid,AncestorLevel=1}}

以上都是用于RelativeSource binding用例。

这是一个ref链接


值得注意的是,对于那些在Silverlight的这种想法中磕磕绊绊的人来说:

Silverlight仅提供这些命令的简化子集


别忘了TemplatedParent:

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>

要么

{Binding RelativeSource={RelativeSource TemplatedParent}}

如果你想绑定到对象的另一个属性:

{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}

想象一下,这种情况下,我们想要一个矩形,它的高度总是等于它的宽度,让我们假设一个正方形。 我们可以使用元素名称来做到这一点

<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}"/>

对于这种情况,我们没有义务提及绑定对象的名称,并且每当高度发生变化时,宽度将始终等于高度。

如果您想将宽度参数设置为高度的一半,则可以通过向绑定标记扩展添加转换器来完成此操作。 现在让我们来想象另一个案例:

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
                   Path=Parent.ActualWidth}"/>

上述情况用于将给定元素的给定属性与其直接父元素的给定属性绑定在一起,因为此元素拥有一个名为Parent的属性。 这导致我们到另一个相对来源模式,即FindAncestor。


我创建了一个库来简化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 : http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

请注意,在'BEFORE'示例中,我用于方法绑定的代码已经通过使用RelayCommand进行了优化,最后我检查的不是WPF的本机部分。 如果没有这个'以前'的例子会更长。


我没有阅读每一个答案,但我只是想添加此信息的情况下,相对源按钮的命令绑定。 当您使用Mode=FindAncestor使用相对源时,绑定必须如下所示:

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"

如果您不在路径中添加DataContext,则在执行时他无法检索该属性。


这是使用这种模式在空数据网格上工作的一个例子。

<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 RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

RelativeSource的默认属性是Mode属性。 这里给出了一组完整的有效值( 来自MSDN ):

  • PreviousData允许您绑定正在显示的数据项目列表中的以前的数据项目(不是包含数据项目的控制项目)。

  • TemplatedParent引用应用模板(其中存在数据绑定元素)的元素。 这与设置TemplateBindingExtension类似,只有在Binding位于模板中时才适用。

  • Self指的是您要在其上设置绑定的元素,并允许您将该元素的一个属性绑定到同一元素上的另一个属性。

  • FindAncestor指数据绑定元素的父链中的祖先。 您可以使用它来绑定到特定类型的祖先或其子类。 如果您要指定AncestorType和/或AncestorLevel,则使用此模式。





relativesource