Установка DataContext в UserControl влияет на привязки в родительском
У меня есть базовый UserControl
, который устанавливает его DataContext
в себя для удобства привязки:
<UserControl x:Class="MyControlLib.ChildControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
</UserControl>
Это используется в родительском файле XAML следующим образом:
<UserControl x:Class="MyControlLib.ParentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ctrl="clr-namespace:MyControlLib">
<ctrl:ChildControl x:Name="ChildName"
PropertyOnChild="{Binding PropertyInParentContext}"/>
</UserControl>
По какой-то причине это дает ошибку привязки, которая, по-видимому, указывает на то, что элемент управления DataContext
родительского элемента влияет на настройку дочернего элемента управления на свой собственный DataContext
.
Ошибка System.Windows.Data: 40: Ошибка пути BindingExpression: свойство PropertyInParentContext не найдено в 'объекте' '' ChildControl '(Name=' ChildName ')'. BindingExpression: Path = PropertyInParentContext; DataItem = 'ChildControl' (Name= 'ChildName'); целевым элементом является "ChildControl" (Name= "ChildName" ); target - свойство 'PropertyOnChild' (тип 'whatever')
Почему "PropertyInParentContext" ищет в дочернем элементе управления, а не в родительском DataContext
?
Если я удалю
DataContext="{Binding RelativeSource={RelativeSource Self}}
из дочернего элемента управления, тогда все работает так, как я ожидал.
Я пропустил что-то очевидное здесь?
Ответы
Ответ 1
Объявление вашего элемента управления и создания экземпляра в основном управляет одним и тем же объектом, все свойства, заданные в объявлении, также устанавливаются на каждом экземпляре. Поэтому, если свойства были "видимыми", так сказать:
<UserControl x:Class="MyControlLib.ParentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ctrl="clr-namespace:MyControlLib">
<ctrl:ChildControl x:Name="ChildName"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
PropertyOnChild="{Binding PropertyInParentContext}"/>
</UserControl>
Вот почему вы не устанавливаете DataContext
из UserControls
, он переопределяет унаследованный DataContext
(и даже обфускает тот факт, что существует другой контекст). Если вы хотите привязать к свойствам UserControl
в своем объявлении, тогда назовите элемент управления и используйте вместо него ElementName
или RelativeSource
-bindings.
Ответ 2
Self
означает UserControl
, поэтому, когда вы устанавливаете DataContext
на Self
, вы устанавливаете DataContext
в объект UserControl
.
Правильный синтаксис для привязки к элементу управления DataContext
будет {Binding RelativeSource={RelativeSource Self}, Path=DataContext}
, однако, поскольку DataContext наследуется родителем, эта привязка абсолютно не нужна в любой ситуации.
Кроме того, если вы привязываете DataContext
к Self.DataContext
, вы, по существу, создаете цикл, в котором значение привязывается к самому себе.