wpf - 從DataTemplate訪問父DataContext
xaml data-binding (4)
我有一個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
屬性。
如何在樣式中指定綁定表達式,以便它可以工作,而不管父數據上下文是集合視圖還是單個項目?
RelativeSource與ElementName
這兩種方法可以達到相同的結果,
RelativeSrouce
Binding="{Binding Path=DataContext.MyBindingProperty,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
此方法在可視樹中查找類型為Window的控件(在本例中),當它發現它時,您基本上可以使用Path=DataContext....
來訪問它的DataContext
。 這種方法的優點是你不需要被綁定到一個名稱上,它是一種動態的方式,但是對你的可視化樹所做的改變會影響這個方法並且可能會破壞它。
的ElementName
Binding="{Binding Path=DataContext.MyBindingProperty, ElementName=MyMainWindow}
這種方法只要你的作用域能夠看到它就可以接受一個固定的靜態Name
,你很好。你應該堅持你的命名約定,不要打破這個方法。這個方法非常簡單,你只需要為您的Window / UserControl指定一個Name="..."
。
儘管所有三種類型( RelativeSource, Source, ElementName
)都可以做同樣的事情,但根據以下MSDN文章,每個類型都可以更好地用於他們自己的專業領域。
在頁面底部的表格中查找每個鏈接的簡要說明以及更多詳細信息的鏈接。
問題是DataTemplate不是應用於它的元素的一部分。
這意味著如果你綁定到模板,你綁定到沒有上下文的東西。
然而,如果你將一個元素放在模板中,那麼當這個元素被應用到父元素時,它會獲得一個上下文,然後該綁定起作用
所以這是行不通的
<DataTemplate >
<DataTemplate.Resources>
<CollectionViewSource x:Key="projects" Source="{Binding Projects}" >
但是這完美地工作
<DataTemplate >
<GroupBox Header="Projects">
<GroupBox.Resources>
<CollectionViewSource x:Key="projects" Source="{Binding Projects}" >
因為在應用數據模板之後,組框被放置在父組件中並且將有權訪問其上下文
所以你所要做的就是從模板中刪除樣式並將其移入模板中的元素
請注意 ,itemcontrol的上下文是不是控件的項目,即ComboBox的ComboBoxItem而不是ComboBox本身,在這種情況下,您應該使用控件ItemContainerStyle
我在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
不能從模板化的項目中訪問,但是由於我沒有找到更好的解決方案,我只是嘗試了一下,並且它工作正常。
我正在尋找如何在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
類型進行篩選。