Подтвердить что ты не робот

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}"> не работает?
  • Каков наилучший способ сделать что-то подобное?
4b9b3361

Ответ 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, который ссылается на ваш элемент управления, чтобы вы могли получить доступ к любым свойствам этого элемента управления, используя относительные привязки.

Ответ 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 для каждой привязки.