DataContext UserControl
Я создаю 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}">
работы? - каков наилучший способ сделать что-то подобное?
5 ответов
для первого, попробуйте:
<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
и для второго вопроса, я думаю, используя ElementName
или AncestorBinding
лучший способ привязать к UserControl
свойства.
почему вы не можете использовать <UserControl DataContext="{RelativeSource Self}">
?
вот как вы будете использовать control
<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, который ссылается на ваш элемент управления, поэтому вы можете получить доступ к любым свойствам этого элемента управления с помощью относительных Привязок.
вы должны использовать
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Color}
для связанных с привязкой данных сомнений всегда ссылаются на это sheet.
http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx
вы можете установить 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>
Я знаю, что на это был дан ответ, но ни одно из объяснений не дает понимания DataContext и как он работает. Эта ссылка делает большую работу для этого.
ВСЕ, ЧТО ВЫ ХОТЕЛИ ЗНАТЬ О ПРИВЯЗКЕ ДАННЫХ В WPF, SILVERLIGHT И WP7 (ЧАСТЬ ВТОРАЯ)
в ответ на ваш вопрос #1
почему <UserControl DataContext="{RelativeSource Self}">
работы?
это резюме приведенной выше ссылки. DataContext не должен быть установлен в Self в элементе UserControl уровень. Это происходит потому, что он нарушает наследование DataContext. Если вы установите его в self и поместите этот элемент управления в окно или другой элемент управления, он не унаследует Windows DataContext.
DataContext наследуется всем нижним элементам XAML и всем XAML UserControls, если он где-то не перезаписан. Установив UserControl DataContext для себя, это перезаписывает DataContext и нарушает наследование. Вместо этого, вложите его один элемент глубоко в 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>
обратите внимание, что после этого Вам не понадобится имя элемента для каждой привязки.