web-dev-qa-db-fra.com

DataContext de UserControl

Je crée un UserControl Je veux utiliser quelque chose comme ceci:

<controls:ColorWithText Color="Red" Text="Red color" />

Jusqu'à présent, j'ai implémenté des contrôles similaires comme celui-ci:

<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 et Text sont des propriétés de dépendance du contrôle défini dans le code. Cela fonctionne, mais spécifier ElementName à chaque fois semble inutile.

Une autre option qui fonctionne utilise

<UserControl x:Class=… DataContext="{Binding ElementName=ThisControl}" Name="ThisControl">

et ne pas spécifier ElementNames, mais cela ne me semble pas non plus être une solution propre.

J'ai deux questions:

  1. Pourquoi <UserControl DataContext="{RelativeSource Self}"> travail?
  2. Quelle est la meilleure façon de faire quelque chose comme ça?
40
svick

Pour le premier, essayez:

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

Et pour la deuxième question, je pense que l'utilisation de ElementName ou AncestorBinding est le meilleur moyen de se lier aux propriétés de UserControl.

59
decyclone

Pourquoi ne pouvez-vous pas utiliser <UserControl DataContext="{RelativeSource Self}">?

Voici comment vous utiliseriez le contrôle

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

Maintenant, comme nous avons codé en dur notre contexte de données dans le contrôle, il tentera plutôt de rechercher la propriété ColorToUse sur l'objet ColorWithText et non sur votre ViewModel, qui sera évidemment échouer.

C'est pourquoi vous ne pouvez pas définir le DataContext sur le contrôle utilisateur. Merci à Brandur de m'avoir fait comprendre cela.

Quelle est la meilleure façon de faire quelque chose comme ça?

Au lieu de cela, vous devez définir le DataContext dans le premier élément d'interface utilisateur enfant de votre contrôle.

Dans votre cas, vous voulez

<StackPanel 
  DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
  Orientation="Horizontal" >

Vous disposez maintenant d'un DataContext qui fait référence à votre contrôle afin que vous puissiez accéder à toutes les propriétés de ce contrôle à l'aide de liaisons relatives.

19
pdross

Vous devriez utiliser

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Color}

pour la liaison de données Les doutes liés se réfèrent toujours à cette fiche.
http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx

13
Prince Ashitaka

Je sais que cela a été répondu, mais aucune des explications ne donne une compréhension de DataContext et comment cela fonctionne. Ce lien fait un excellent travail pour cela.

TOUT CE QUE VOUS VOULIEZ SAVOIR SUR LA LIAISON DE DONNÉES DANS WPF, SILVERLIGHT ET WP7 (DEUXIÈME PARTIE)

En réponse à votre question # 1

Pourquoi <UserControl DataContext="{RelativeSource Self}"> travail?

Ceci est un résumé du lien ci-dessus. DataContext ne doit pas être défini sur Self au niveau de l'élément UserControl. Cela est dû au fait qu'il rompt l'héritage du DataContext. Si vous le définissez sur self et que vous placez ce contrôle sur une fenêtre ou un autre contrôle, il n'héritera pas du DataContext Windows.

DataContext est hérité de tous les éléments inférieurs du XAML et de tous les XAML des UserControls, sauf s'il est remplacé quelque part. En définissant UserControl DataContext sur lui-même, cela écrase le DataContext et rompt l'héritage. Au lieu de cela, imbriquez-le d'un élément profondément dans le XAML, dans votre cas, le StackPanel. Placez la liaison DataContext ici et liez-la à UserControl. Cela préserve l'héritage.

Voir également ce lien ci-dessous pour une explication détaillée de cela.

N MOTIF SIMPLE POUR CRÉER DES CONTRÔLES D'UTILISATION RÉUTILISABLES DANS WPF/SILVERLIGHT

En réponse à votre question # 2
Quelle est la meilleure façon de faire quelque chose comme ça?

Voir l'exemple de code ci-dessous.

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

Notez qu'une fois que vous faites cela, vous n'aurez plus besoin de ElementName sur chaque liaison.

12
jdawiz

Vous pouvez définir le datacontext sur self au niveau du constructeur lui-même.

public ColorWithText()
{
 InitializeComponent();
 DataContext = this;
}

Maintenant, vous pouvez simplement dire

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" >
        <Border Width="15" Height="15" Background="{Binding Color}" />
        <TextBlock Text="{Binding Text}" />
    </StackPanel>
</UserControl>
10
biju