从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并按ItemsControl
types进行筛选。
RelativeSource与ElementName
这两种方法可以达到同样的效果,
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每个链接的简要说明以及更详细的链接。