UserControl's DataContext - PullRequest
       14

UserControl's DataContext

39 голосов
/ 22 февраля 2011

Я создаю 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, но это не похоже намне тоже чистое решение.

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

  1. Почему не работает <UserControl DataContext="{RelativeSource Self}">? 1023 *
  2. Как лучше всего сделать что-то вродеэто?

Ответы [ 5 ]

57 голосов
/ 22 февраля 2011

Для первого попробуйте:

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">

И для второго вопроса, я думаю, использование ElementName или AncestorBinding - лучший способ связать свойства UserControl.

19 голосов
/ 07 февраля 2012

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

13 голосов
/ 22 февраля 2011

Вы должны использовать

{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

10 голосов
/ 22 февраля 2017

Я знаю, что на этот вопрос ответили, но ни одно из объяснений не дает понимания DataContext и того, как он работает.Эта ссылка делает большую работу для этого.

ВСЕ, ЧТО ВЫ ХОТИТЕ ЗНАТЬ О БАЗЕ ДАННЫХ В WPF, SILVERLIGHT И WP7 (ЧАСТЬ ВТОРАЯ)

В ответ на ваш вопрос # 1

Почему <UserControl DataContext="{RelativeSource Self}"> не работает?

Это краткое изложение вышеуказанной ссылки.DataContext не должен быть установлен в Self на уровне элемента UserControl.Это потому, что он нарушает наследование DataContext.Если вы установите для него значение self и поместите этот элемент управления в Window или другой элемент управления, он не будет наследовать Windows DataContext.

DataContext наследуется всем нижним элементам XAML и всем XAML UserControls, если он не перезаписан где-либо.При установке UserControl DataContext на себя, это перезаписывает DataContext и нарушает Наследование.Вместо этого вложите один элемент в XAML, в вашем случае, в StackPanel.Поместите здесь привязку DataContext и привяжите ее к UserControl.Это сохраняет наследство.

См. Также приведенную ниже ссылку для подробного объяснения этого.

ПРОСТОЙ РИСУНОК ДЛЯ СОЗДАНИЯ ПОВТОРНЫХ ИСПОЛЬЗОВАННЫХ УПРАВЛЕНИЙ В WPF / SILVERLIGHT

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

10 голосов
/ 22 февраля 2011

Вы можете установить для 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...