从DataTemplate访问父DataContext

我有一个ListBox绑定到ViewModel上的子集合。 列表框项目根据父ViewModel上的属性在数据模板中进行样式设置:

<Style x:Key="curveSpeedNonConstantParameterCell">
   <Style.Triggers>
      <DataTrigger Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, 
          ElementName=someParentElementWithReferenceToRootDataContext}" 
          Value="True">
          <Setter Property="Control.Visibility" Value="Hidden"></Setter>
      </DataTrigger>
   </Style.Triggers>
</Style>

我得到以下输出错误:

System.Windows.Data Error: 39 : BindingExpression path error: 
 'CurveSpeedMustBeSpecified' property not found on 
   'object' ''BindingListCollectionView' (HashCode=20467555)'. 
 BindingExpression:Path=DataContext.CurveSpeedMustBeSpecified; 
 DataItem='Grid' (Name='nonConstantCurveParametersGrid');
 target element is 'TextBox' (Name=''); 
 target property is 'NoTarget' (type 'Object')

因此,如果我将绑定表达式更改为"Path=DataContext.CurrentItem.CurveSpeedMustBeSpecified"它将起作用,但只有父用户控件的datacontext是BindingListCollectionView 。 这是不可接受的,因为用户控件的其余部分会自动绑定到BindingList上的CurrentItem属性。

如何在样式中指定绑定表达式,以便它可以工作,而不管父数据上下文是集合视图还是单个项目?


我在Silverlight的相关源代码中遇到了问题。 搜索和阅读后,我没有找到一个合适的解决方案,没有使用一些额外的绑定库。 但是,这是另一种通过直接引用您知道数据上下文的元素来访问父DataContext的方法。 它使用Binding ElementName并且工作得很好,只要您尊重自己的命名,并且不会跨组件重复使用templates / styles

<ItemsControl x:Name="level1Lister" ItemsSource={Binding MyLevel1List}>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Button Content={Binding MyLevel2Property}
              Command={Binding ElementName=level1Lister,
                       Path=DataContext.MyLevel1Command}
              CommandParameter={Binding MyLevel2Property}>
      </Button>
    <DataTemplate>
  <ItemsControl.ItemTemplate>
</ItemsControl>

如果将按钮放入Style / Template这也适用:

<Border.Resources>
  <Style x:Key="buttonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Button Command={Binding ElementName=level1Lister,
                                   Path=DataContext.MyLevel1Command}
                  CommandParameter={Binding MyLevel2Property}>
               <ContentPresenter/>
          </Button>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</Border.Resources>

<ItemsControl x:Name="level1Lister" ItemsSource={Binding MyLevel1List}>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Button Content="{Binding MyLevel2Property}" 
              Style="{StaticResource buttonStyle}"/>
    <DataTemplate>
  <ItemsControl.ItemTemplate>
</ItemsControl>

起初我以为父元素的x:Names不能从模板化的项目中访问,但是由于我没有找到更好的解决方案,我只是尝试了一下,并且它工作正常。


您可以使用RelativeSource来查找父元素,就像这样 -

Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, 
RelativeSource={RelativeSource AncestorType={x:Type local:YourParentElementType}}}"

看到这个SO问题关于RelativeSource更多细节。


我正在寻找如何在WPF中做类似的事情,并且我得到了这个解决方案:

<ItemsControl ItemsSource="{Binding MyItems,Mode=OneWay}">
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel Orientation="Vertical" />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <RadioButton 
            Content="{Binding}" 
            Command="{Binding Path=DataContext.CustomCommand, 
                        RelativeSource={RelativeSource Mode=FindAncestor,      
                        AncestorType={x:Type ItemsControl}} }"
            CommandParameter="{Binding}" />
    </DataTemplate>
</ItemsControl.ItemTemplate>

我希望这适用于其他人。 我有一个自动设置为ItemsControls的数据上下文,并且此数据上下文具有两个属性: MyItems (其为集合)和一个命令'CustomCommand'。 由于ItemTemplate正在使用DataTemplate ,所以上层的DataContext不能直接访问。 然后,获取父级的DC的解决方法是使用相对路径并按ItemsControl类型进行筛选。

链接地址: http://www.djcxy.com/p/34467.html

上一篇: Access parent DataContext from DataTemplate

下一篇: Send an audio stream from Wowza to a speech to text cloud service