У меня есть 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
автоматически.
Как я могу указать выражение привязки внутри стиля, чтобы оно работало независимо от того, является ли контекст родительских данных представлением коллекции или отдельным элементом?
Вы можете использовать
RelativeSource
для поиска родительского элемента, например:См. Этот вопрос SO для получения более подробной информации о
RelativeSource
.источник
Mode=FindAncestor
чтобы он работал, но это работает и намного лучше в сценарии MVVM, поскольку позволяет избежать элементов управления именами.Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:YourParentElementType}}}"
RelativeSource против ElementName
Эти два подхода позволяют достичь одного и того же результата,
RelativeSrouce
Этот метод ищет элемент управления типа Window (в этом примере) в визуальном дереве, и когда он его находит, вы можете получить к нему доступ,
DataContext
используя расширениеPath=DataContext....
. Плюсы этого метода в том, что вам не нужно быть привязанным к имени, и это своего рода динамический, однако изменения, внесенные в ваше визуальное дерево, могут повлиять на этот метод и, возможно, сломать его.ElementName
Этот метод относится к твердой статике,
Name
поэтому, пока ваша область видимости может видеть это, все в порядке. Вы должны придерживаться своего соглашения об именах, чтобы не нарушать этот метод, конечно. Подход очень прост, и все, что вам нужно, это указать aName="..."
для вашего Window / UserControl.Хотя все три типа (
RelativeSource, Source, ElementName
) способны делать одно и то же, но, согласно следующей статье MSDN, каждый из них лучше использовать в своей области специализации.Как: указать источник привязки
Найдите краткое описание каждого из них и ссылку на более подробную информацию в таблице внизу страницы.
источник
Я искал, как сделать что-то подобное в WPF, и получил это решение:
Я надеюсь, что это сработает для кого-нибудь еще. У меня есть контекст данных, который автоматически устанавливается в ItemsControls, и этот контекст данных имеет два свойства:
MyItems
-который является коллекцией- и одну команду CustomCommand. ПосколькуItemTemplate
используется aDataTemplate
,DataContext
прямой доступ к верхним уровням невозможен. Тогда обходной путь для получения DC родительского элемента - использовать относительный путь и фильтровать поItemsControl
типу.источник
проблема в том, что DataTemplate не является частью применяемого к нему элемента.
это означает, что если вы привязываетесь к шаблону, вы привязываетесь к чему-то, что не имеет контекста.
однако если вы поместите элемент в шаблон, тогда, когда этот элемент применяется к родительскому, он получает контекст, и привязка затем работает
так что это не сработает
но это отлично работает
потому что после применения таблички данных групповой ящик помещается в родительский элемент и будет иметь доступ к его контексту
поэтому все, что вам нужно сделать, это удалить стиль из шаблона и переместить его в элемент в шаблоне
обратите внимание, что контекст для элемента управления - это элемент, а не элемент управления, т.е. ComboBoxItem для ComboBox, а не сам ComboBox, и в этом случае вместо этого следует использовать элементы управления ItemContainerStyle
источник
Да, вы можете решить эту проблему с помощью
ElementName=Something
предложенный Жювом.НО!
Если дочерний элемент (для которого вы используете такую привязку) является пользовательским элементом управления, который использует то же имя элемента, что и вы указали в родительском элементе управления, то привязка переходит к неправильному объекту !!
Я знаю, что этот пост не является решением, но я думал, что все, кто использует ElementName в привязке, должны знать об этом, поскольку это возможная ошибка времени выполнения.
источник