从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') 

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

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

我在Silverlight中的相对来源有问题。 search和阅读后,我没有find一个合适的解决scheme,没有使用一些额外的绑定库。 但是,这里是另一种通过直接引用你知道数据上下文的元素来访问父DataContext的方法。 它使用Binding ElementName并且工作得很好,只要你尊重你自己的命名,并且不会在组件间重复使用模板/样式:

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

这也适用于如果你把button进入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是不能从一个模板项目内访问的,但是因为我没有find更好的解决scheme,我只是试了一下,而且工作正常。

我希望这个解决scheme有帮助

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

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

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

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

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

我希望这对别人有用。 我有一个自动设置ItemsControl的数据上下文,这个数据上下文有两个属性: MyItems – 这是一个集合,和一个命令“CustomCommand”。 由于ItemTemplate正在使用DataTemplate ,所以上层的DataContext不能直接访问。 然后,获取父级的DC的解决方法是使用相对path并按ItemsControltypes进行筛选。

RelativeSourceElementName

这两种方法可以达到同样的效果,

RelativeSrouce

 Binding="{Binding Path=DataContext.MyBindingProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 

这个方法在Visual树中寻找一个Windowtypes的控件(在这个例子中),当它发现它的时候,基本上可以使用Path=DataContext....来访问它的DataContext 。 这个方法的优点是你不需要被绑定到一个名字上,它是一种dynamic的,然而,对你的可视化树所做的改变会影响这个方法,并且可能会破坏它。

的ElementName

 Binding="{Binding Path=DataContext.MyBindingProperty, ElementName=MyMainWindow} 

这个方法只要是一个固定的静态Name ,只要你的范围可以看到,你就可以了。你应该坚持你的命名约定,不要打破这个方法。这个方法非常简单,你只需要为您的Window / UserControl指定一个Name="..."

虽然所有这三种types( RelativeSource, Source, ElementName )都可以做同样的事情,但根据以下MSDN文章,每一个更适合在自己的专业领域使用。

如何:指定绑定源

请在页面底部的表格中find每个链接的简要说明以及更详细的链接。