У меня есть 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 «
это работает, но только до тех пор, пока текст данных родительского пользовательского элемента управления является BindingListCollectionView
. Это недопустимо, поскольку остальная часть пользовательского элемента управления автоматически связывается со свойствами CurrentItem
в BindingList
.
Как указать выражение привязки внутри стиля, чтобы оно работало независимо от того, является ли родительский контекст данных представлением коллекции или отдельным элементом?
У меня возникли проблемы с относительным источником в Silverlight. После поиска и чтения я не нашел подходящего решения без использования дополнительной библиотеки привязки. Но вот другой подход для получения доступа к родительскому 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>
Это также работает, если вы поместите кнопку в Стиль
/ Шаблон
:
<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: Имена
родительских элементов не являются доступный из шаблонного элемента, но, поскольку я не нашел лучшего решения, я просто попробовал, и он отлично работает.
Вы можете использовать RelativeSource
, чтобы найти родительский элемент, например:
Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified,
RelativeSource={RelativeSource AncestorType={x:Type local:YourParentElementType}}}"
См. этот вопрос SO для получения дополнительных сведений о RelativeSource
.