Como uso RelativeSource
com ligações WPF e quais são os diferentes casos de uso?
.net
wpf
xaml
data-binding
relativesource
David Schmitt
fonte
fonte
AncestorType
.FindAncestor
, antesAncestorType
, recebo o seguinte erro: "O RelativeSource não está no modo FindAncestor". (No VS2013, versão comunitária){Binding Path=DataContext.SomeProperty, RelativeSource=...
. Isso foi algo inesperado para mim como novato quando estava tentando vincular ao DataContext de um pai dentro de um DataTemplate.O atributo padrão de
RelativeSource
é aMode
propriedade Um conjunto completo de valores válidos é fornecido aqui ( do MSDN ):PreviousData Permite vincular o item de dados anterior (não o controle que contém o item de dados) na lista de itens de dados que estão sendo exibidos.
TemplatedParent Refere-se ao elemento ao qual o modelo (no qual o elemento ligado a dados existe) é aplicado. É semelhante à configuração de TemplateBindingExtension e é aplicável apenas se a Vinculação estiver dentro de um modelo.
Auto Refere-se ao elemento no qual você está definindo a ligação e permite vincular uma propriedade desse elemento a outra propriedade no mesmo elemento.
FindAncestor Refere-se ao ancestral na cadeia pai do elemento ligado a dados. Você pode usar isso para ligar-se a um ancestral de um tipo específico ou de suas subclasses. Este é o modo que você usa se deseja especificar AncestorType e / ou AncestorLevel.
fonte
Aqui está uma explicação mais visual no contexto de uma arquitetura MVVM:
fonte
{Binding Message}
(um pouco mais simples ...)Path=DataContext.Message
para fazer a ligação funcionar. Isso faz sentido, já que você pode fazer ligações relativas à largura / altura / etc. de um controle.Bechir Bejaoui expõe os casos de uso do RelativeSources no WPF em seu artigo aqui :
fonte
ListView
. O pai tem mais 2ListView
níveis abaixo dele. Isso me ajudou a impedir a transmissão de dados em cada vm subsequente de cadaListView
umDataTemplate
No WPF, a
RelativeSource
associação expõe trêsproperties
para definir:1. Modo: Este é um
enum
que pode ter quatro valores:2. AncestorType: quando mode é,
FindAncestor
então, defina que tipo de ancestral3. AncestorLevel: quando mode é
FindAncestor
qual o nível de ancestral (se houver dois mesmos tipos de paisvisual tree
)Aqui está um link de referência .
fonte
Não se esqueça do TemplatedParent:
ou
fonte
É digno de nota que, para aqueles que se deparam com esse pensamento do Silverlight:
O Silverlight oferece apenas um subconjunto reduzido desses comandos
fonte
Criei uma biblioteca para simplificar a sintaxe de ligação do WPF, facilitando o uso do RelativeSource. Aqui estão alguns exemplos. Antes:
Depois de:
Aqui está um exemplo de como a ligação do método é simplificada. Antes:
Depois de:
Você pode encontrar a biblioteca aqui: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
Observe no exemplo 'ANTES' que eu uso para ligação de método que o código já foi otimizado usando a
RelayCommand
última verificação que não fiz parte do WPF. Sem isso, o exemplo 'ANTES' teria sido ainda mais longo.fonte
Algumas partes úteis:
Veja como fazer isso principalmente no código:
Copiei isso amplamente da Binding Relative Source no código Behind .
Além disso, a página MSDN é muito boa no que diz respeito aos exemplos: Classe RelativeSource
fonte
Acabei de publicar outra solução para acessar o DataContext de um elemento pai no Silverlight que funciona para mim. Ele usa
Binding ElementName
.fonte
Não li todas as respostas, mas só quero adicionar essas informações no caso de ligação de comando de origem relativa de um botão.
Quando você usa uma fonte relativa com
Mode=FindAncestor
, a ligação deve ser como:Se você não adicionar o DataContext ao seu caminho, no tempo de execução, ele não poderá recuperar a propriedade.
fonte
Este é um exemplo do uso desse padrão que funcionou para mim em datagrids vazios.
fonte
Se um elemento não fizer parte da árvore visual, o RelativeSource nunca funcionará.
Nesse caso, você precisa tentar uma técnica diferente, pioneira em Thomas Levesque.
Ele tem a solução em seu blog em [WPF] Como vincular aos dados quando o DataContext não é herdado . E funciona absolutamente brilhante!
No caso improvável de seu blog estar inativo, o Apêndice A contém uma cópia espelhada de seu artigo .
Por favor, não comente aqui, por favor, comente diretamente em seu blog .
Apêndice A: Espelho da postagem do blog
A propriedade DataContext no WPF é extremamente útil, porque é automaticamente herdada por todos os filhos do elemento em que você o atribui; portanto, você não precisa defini-lo novamente em cada elemento que deseja vincular. No entanto, em alguns casos, o DataContext não está acessível: isso acontece com elementos que não fazem parte da árvore visual ou lógica. Pode ser muito difícil vincular uma propriedade nesses elementos…
Vamos ilustrar com um exemplo simples: queremos exibir uma lista de produtos em um DataGrid. Na grade, queremos poder mostrar ou ocultar a coluna Preço, com base no valor de uma propriedade ShowPrice exposta pelo ViewModel. A abordagem óbvia é vincular a visibilidade da coluna à propriedade ShowPrice:
Infelizmente, alterar o valor de ShowPrice não tem efeito e a coluna está sempre visível ... por quê? Se olharmos para a janela Saída no Visual Studio, notamos a seguinte linha:
Podemos tentar ajustar a ligação para obter o resultado desejado, por exemplo, configurando o RelativeSource para o próprio DataGrid:
Ou podemos adicionar uma CheckBox vinculada a ShowPrice e tentar vincular a visibilidade da coluna à propriedade IsChecked especificando o nome do elemento:
Mas nenhuma dessas soluções alternativas parece funcionar, sempre obtemos o mesmo resultado…
Neste ponto, parece que a única abordagem viável seria alterar a visibilidade da coluna no code-behind, o que geralmente preferimos evitar ao usar o padrão MVVM ... Mas não vou desistir tão cedo, pelo menos não enquanto existem outras opções a considerar 😉
A solução para o nosso problema é realmente bastante simples e tira proveito da classe Freezable. O objetivo principal desta classe é definir objetos que tenham um estado modificável e somente leitura, mas o recurso interessante em nosso caso é que objetos Freezable podem herdar o DataContext mesmo quando não estão na árvore visual ou lógica. Não sei o mecanismo exato que permite esse comportamento, mas vamos tirar proveito dele para fazer nossa ligação funcionar ...
A idéia é criar uma classe (chamei-o de BindingProxy por razões que devem se tornar óbvias muito em breve) que herda o Freezable e declara uma propriedade de dependência de dados:
Em seguida, podemos declarar uma instância dessa classe nos recursos do DataGrid e vincular a propriedade Data ao DataContext atual:
A última etapa é especificar esse objeto BindingProxy (facilmente acessível com StaticResource) como a Origem da ligação:
Observe que o caminho de ligação foi prefixado com "Dados", pois o caminho agora é relativo ao objeto BindingProxy.
A ligação agora funciona corretamente e a coluna é mostrada ou ocultada corretamente com base na propriedade ShowPrice.
fonte