Eu tenho um ListBox
que se liga a uma coleção filho em um ViewModel. Os itens da caixa de listagem são estilizados em um datatemplate com base em uma propriedade no ViewModel pai:
<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>
Recebo o seguinte erro de saída:
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')
Portanto, se eu alterar a expressão de ligação, "Path=DataContext.CurrentItem.CurveSpeedMustBeSpecified"
ela funcionará, mas apenas enquanto o texto de dados do controle de usuário pai for um BindingListCollectionView
. Isso não é aceitável porque o restante do controle do usuário se liga às propriedades do CurrentItem
no BindingList
automaticamente.
Como posso especificar a expressão de ligação dentro do estilo para que funcione independentemente do contexto de dados pai ser uma exibição de coleção ou um único item?
Você pode usar
RelativeSource
para encontrar o elemento pai, como este -Veja esta pergunta do SO para mais detalhes sobre
RelativeSource
.fonte
Mode=FindAncestor
para que funcionasse, mas funciona e é muito melhor em um cenário MVVM porque evita controles de nomenclatura.Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:YourParentElementType}}}"
RelativeSource vs. ElementName
Essas duas abordagens podem alcançar o mesmo resultado,
RelativeSrouce
Este método procura um controle do tipo Window (neste exemplo) na árvore visual e quando o encontra você basicamente pode acessá-lo
DataContext
usando oPath=DataContext....
. Os prós sobre esse método é que você não precisa estar vinculado a um nome e é meio dinâmico; no entanto, as alterações feitas em sua árvore visual podem afetar esse método e possivelmente quebrá-lo.ElementName
Este método se refere a uma estática sólida
Name
então, desde que seu escopo possa ver, você está bem. Você deve seguir sua convenção de nomenclatura para não quebrar este método, é claro. A abordagem é bastante simples e tudo que você precisa é especificar aName="..."
para sua janela / controle de usuário.Embora todos os três tipos (
RelativeSource, Source, ElementName
) sejam capazes de fazer a mesma coisa, mas de acordo com o seguinte artigo do MSDN, cada um deve ser usado em sua própria área de especialidade.Como: Especificar a fonte de ligação
Encontre a breve descrição de cada um e um link para mais detalhes na tabela na parte inferior da página.
fonte
Eu estava pesquisando como fazer algo semelhante no WPF e encontrei esta solução:
Espero que funcione para outra pessoa. Eu tenho um contexto de dados que é definido automaticamente para ItemsControls, e esse contexto de dados tem duas propriedades:
MyItems
-que é uma coleção- e um comando 'CustomCommand'. PorItemTemplate
estar usando umDataTemplate
, oDataContext
dos níveis superiores não está diretamente acessível. Em seguida, a solução alternativa para obter o DC do pai é usar um caminho relativo e filtrar porItemsControl
tipo.fonte
o problema é que um DataTemplate não faz parte de um elemento aplicado a ele.
isso significa que se você se vincular ao modelo, estará vinculando a algo que não tem contexto.
no entanto, se você colocar um elemento dentro do modelo, quando esse elemento for aplicado ao pai, ele ganhará um contexto e a ligação funcionará
então isso não vai funcionar
mas isso funciona perfeitamente
porque depois que o datatemplate é aplicado, o groupbox é colocado no pai e terá acesso ao seu contexto
então tudo que você precisa fazer é remover o estilo do modelo e movê-lo para um elemento no modelo
observe que o contexto de um controle de itens é o item e não o controle, isto é, ComboBoxItem para ComboBox e não o próprio ComboBox, caso em que você deve usar os controles ItemContainerStyle
fonte
Sim, você pode resolver isso usando o
ElementName=Something
sugerido pela Juve.MAS!
Se um elemento filho (no qual você usa esse tipo de ligação) é um controle de usuário que usa o mesmo nome de elemento que você especificou no controle pai, a ligação vai para o objeto errado !!
Sei que este post não é uma solução, mas achei que todos que usam o ElementName na ligação deveriam saber disso, já que é um possível bug de runtime.
fonte