UserControl DataContext
Я создаю UserControl
Я хочу использовать что-то вроде этого:
<controls:ColorWithText Color="Red" Text="Red color" />
До сих пор я реализовал аналогичные элементы управления, например:
<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
<StackPanel Orientation="Horizontal" >
<Border Width="15" Height="15" Background="{Binding Color, ElementName=ThisControl}" />
<TextBlock Text="{Binding Text, ElementName=ThisControl}" />
</StackPanel>
</UserControl>
где Color
и Text
- это свойства зависимостей элемента управления, определенного в коде. Это работает, но указание ElementName
каждый раз кажется ненужным.
Другим вариантом, который работает, является использование
<UserControl x:Class=… DataContext="{Binding ElementName=ThisControl}" Name="ThisControl">
и не указывая ElementName
s, но это тоже не похоже на чистое решение.
У меня есть два вопроса:
- Почему
<UserControl DataContext="{RelativeSource Self}">
не работает?
- Каков наилучший способ сделать что-то подобное?
Ответы
Ответ 1
Для первого, попробуйте:
<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
И для второго вопроса, я думаю, что использование ElementName
или AncestorBinding
- лучший способ привязки к свойствам UserControl
.
Ответ 2
Почему вы не можете использовать <UserControl DataContext="{RelativeSource Self}">
?
Вот как вы бы использовали элемент управления
<Grid DataContext="{StaticResource ViewModel}">
<!-- Here we'd expect this control to be bound to -->
<!-- ColorToUse on our ViewModel resource -->
<controls:ColorWithText Color="{Binding ColorToUse}" />
</Grid>
Теперь, поскольку мы жестко закодировали наш контекст данных в элементе управления, вместо этого он попытается найти свойство ColorToUse в объекте ColorWithText, а не вашей ViewModel, который, очевидно, не удастся.
Вот почему вы не можете установить DataContext в пользовательский элемент управления. Благодаря Brandur за то, что я понял это.
Каков наилучший способ сделать что-то вроде этого?
Вместо этого вы должны установить DataContext в первом дочернем элементе пользовательского интерфейса в вашем элементе управления.
В вашем случае вы хотите
<StackPanel
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Orientation="Horizontal" >
Теперь у вас есть DataContext, который ссылается на ваш элемент управления, чтобы вы могли получить доступ к любым свойствам этого элемента управления, используя относительные привязки.
Ответ 3
Вы должны использовать
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Color}
для привязки данных Связанные сомнения всегда ссылаются на этот лист.
http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx
Ответ 4
Вы можете установить datacontext в self в самом конструкторе.
public ColorWithText()
{
InitializeComponent();
DataContext = this;
}
Теперь вы можете просто сказать
<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
<StackPanel Orientation="Horizontal" >
<Border Width="15" Height="15" Background="{Binding Color}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</UserControl>
Ответ 5
Я знаю, что это ответ, но ни одно из объяснений не дает понимания DataContext и как оно работает. Эта ссылка делает отличную работу для этого.
ВСЕ, ЧТО ВЫ ХОТИТЕ ЗНАТЬ О ДАННЫХ В WPF, SILVERLIGHT и WP7 (ЧАСТЬ ВТОРАЯ)
В ответ на ваш вопроС# 1
Почему не работает <UserControl DataContext="{RelativeSource Self}">
?
Это краткое изложение приведенной выше ссылки.
DataContext не должен быть установлен на уровень Self at UserControl Element. Это связано с тем, что он нарушает наследование DataContext. Если вы настроили его на себя, и вы поместите этот элемент управления в окно или другой элемент управления, он не наследует Windows DataContext.
DataContext наследуется ко всем нижним элементам XAML и ко всем XAML UserControls, если он не перезаписан где-то. Установив UserControl DataContext для себя, это перезаписывает DataContext и ломает Inheritance. Вместо этого вложите в него один элемент в XAML, в вашем случае - StackPanel. Поместите привязку DataContext и привяжите ее к UserControl. Это сохраняет Наследие.
См. также эту ссылку ниже для подробного объяснения этого.
ПРОСТОЙ ОБРАЗЕЦ ДЛЯ СОЗДАНИЯ ВОЗМОЖНЫХ ПОЛЬЗОВАТЕЛЕЙ USERCONTROLS в WPF/SILVERLIGHT
В ответ на ваш вопрос №2
Каков наилучший способ сделать что-то подобное?
См. пример кода ниже.
<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
<StackPanel Orientation="Horizontal" DataContext={Binding ElementName=ThisControl}>
<Border Width="15" Height="15" Background="{Binding Color" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
Обратите внимание: если вы сделаете это, вам не понадобится ElementName для каждой привязки.