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">

и не указывать ElementNames, но это не кажется мне чистым решением любой.

у меня два вопроса:

  1. почему <UserControl DataContext="{RelativeSource Self}"> работы?
  2. каков наилучший способ сделать что-то подобное?

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>

обратите внимание, что после этого Вам не понадобится имя элемента для каждой привязки.