Привязка к предкам из ResourceDictionary
-
20-09-2019 - |
Вопрос
Как я могу привязаться к UserControl
собственность изнутри ResourceDictionary
?Я хочу, чтобы объект, который я объявляю в своих ресурсах, имел то же самое DataContext
как UserControl
он содержится в:
<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>
Во время выполнения я получаю ошибку:
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')
Решение
Мой обходной путь заключался в том, чтобы установить DataContext
ресурса в выделенном коде.
.xaml
<local:SomeType x:Key="SomeKey" SomeProperty="{Binding ... }" />
.xaml.cs
public SomeControl()
{
InitializeComponent();
((SomeType)this.Resources["SomeKey"]).DataContext = this;
}
Другие советы
При использовании FindAncestor целевой элемент должен быть потомком (логическим или визуальным) источника.Ваш объект не отображается ни в визуальном, ни в логическом дереве, он просто находится в ресурсах.Таким образом, вы не можете использовать RelativeSource с FindAncestor для своего объекта.
Однако вы можете использовать ElementName в своей привязке.Что-то вроде этого должно работать:
<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>
Набор х: общий="False", это будет клонировать ресурс при каждом использовании и делать его дочерним элементом вашего элемента, позволяя использовать привязки.
<local:SomeClass
x:Key="SomeClass"
x:Shared="False"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
Я думаю, что вы ищете просто {Binding}, который привязывается к унаследованному DataContext.Вот пример, хотя и немного странный, показывающий, как можно получить цвет посредством привязки к 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>
Я бы создал прикрепленное поведение (ContextualizeResourceBehavior) для пользовательского элемента управления и указал ключ ресурса для этого прикрепленного поведения.Поведение будет искать ресурс (не уверен, что вы сможете сделать это при подключении, в противном случае вам нужно будет подключить событие Loaded) и передавать контекст данных.
когда вы добавляете свой ресурс в визуальное дерево, он должен наследовать контекст данных.но...посмотри на элемент шпиона он может просто делать то, что вам нужно.