Ligação aos ancestrais de dentro de um recurso
-
20-09-2019 - |
Pergunta
Como posso ligar a um UserControl
propriedade de dentro de sua ResourceDictionary
? Eu quero um objeto que declaro em meus recursos para ter o mesmo DataContext
Enquanto o UserControl
está contido em:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Some.Namespace"
DataContext="{Binding Path=ViewModel, RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
<local:SomeClass
x:Key="SomeClass"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</UserControl.Resources>
</UserControl>
Em tempo de execução, recebo o erro:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='UserControl', AncestorLevel='1''. BindingExpression:Path=DataContext; DataItem=null; target element is 'SomeClass' (Name=''); target property is 'DataContext' (type 'Object')
Solução
Minha solução alternativa era definir o DataContext
do recurso no código-behind.
.xaml
<local:SomeType x:Key="SomeKey" SomeProperty="{Binding ... }" />
.xaml.cs
public SomeControl()
{
InitializeComponent();
((SomeType)this.Resources["SomeKey"]).DataContext = this;
}
Outras dicas
Ao usar o FindAncestor, o elemento de destino precisa ser um descendente (lógico ou visual) da fonte. Seu objeto não aparece na árvore visual ou lógica, está simplesmente nos recursos. Portanto, você não pode usar o RelativeRce com o FindAncestor para o seu objeto.
Você pode usar o ElementName em sua ligação. Algo assim deve funcionar:
<UserControl x:Name="userControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Some.Namespace"
DataContext="{Binding Path=ViewModel, RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
<local:SomeClass
x:Key="SomeClass"
DataContext="{Binding Path=DataContext, ElementName=userControl}" />
</UserControl.Resources>
</UserControl>
Definir X: compartilhado= "Falso", isso clonará o recurso de cada uso e o tornará um filho do seu elemento, permitindo o uso de ligações.
<local:SomeClass
x:Key="SomeClass"
x:Shared="False"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
Eu acho que o que você está procurando é apenas {binding} que se liga ao datacontext herdado. Aqui está um exemplo, embora um pouco estranho mostre como você pode pegar uma cor através da ligação ao DataContext:
<Window x:Class="AncestorBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Blue" />
</Window.Resources>
<StackPanel>
<Button DataContext="{Binding Source={StaticResource MyBrush}}" Content="My Button">
<Button.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{Binding}" />
</Style>
</Button.Resources>
</Button>
</StackPanel>
</Window>
O que eu faria é criar um comportamento anexado (contextualizeSourceBeHavior) no controle do usuário e especificar a chave do recurso nesse comportamento anexado. O comportamento procuraria o recurso (não tenho certeza se você seria capaz de fazê -lo, se não precisará conectar o evento carregado) e transferir o contexto de dados.
Quando você adiciona seu recurso à árvore visual, ele deve herdar o contexto de dados. Mas ... dê uma olhada em elemento espião Pode fazer o que você precisa.