2011-08-31 3 views
26

Dans la suite de la question Linking DataContext with another property in WPF.À quoi sert DataContext?

J'ai été très surpris de la fin de la recherche pour savoir que quand on écrit quelque chose comme ça:

<Label Content="{Binding Path=Name}" /> 

La DataContext contre laquelle la propriété est Content binded est du contrôle Label lui-même! Le fait qu'il fonctionne toujours est dû à l'héritage par défaut de la valeur DataContext du parent le plus proche.

Mais si vous avez cette étiquette enveloppée dans un contrôle personnalisé, et vous ne voulez pas lier vos données à la propriété DataContext de ce contrôle, vous aimeriez plus susceptibles d'avoir:

<Controls:SearchSettings Settings="{Binding Path=Settings}" /> 

Et vous voilà. Maintenant, vous devez définir Settings comme DataContext pour le contrôle SearchSettings, pour Label à l'intérieur de lier, mais vous ne pouvez pas, car cela déclenchera re-liaison de la propriété Settings.

Je ne vois pas le point dans le mélange des propriétés de liaison en utilisant différentes sources: DataContext, par ElementName, etc. Alors, pourquoi aurais-je jamais utiliser DataContext?

Répondre

78

Lorsque vous écrivez

<Label name="myLabel" Content="{Binding Path=Name}" /> 

vous liez à myLabel.DataContext.Name, et pas myLabel.Name.

Le XAML dans WPF est juste une jolie interface utilisateur pour afficher et interagir avec les données réelles, autrement connu comme le DataContext. Le but d'autres sources de liaison (RelativeSource, ElementName, etc) est de pointer vers une autre propriété qui n'existe pas dans les contrôles actuels DataContext


Supposons que vous ayez une fenêtre. Sans définir le DataContext, la fenêtre s'affiche toujours mais il n'y a pas de données derrière elle.

Supposons maintenant de définir myWindow.DataContext = new ClassA();. Maintenant, les données que la fenêtre affiche est ClassA.Si ClassA a une propriété appelée Name, je pourrais écrire une étiquette et la lier à Name (comme votre exemple), et n'importe quelle valeur est stockée dans ClassA.Name serait affichée.

Maintenant, supposons ClassA a une propriété de ClassB et les deux classes ont une propriété appelée Name. Voici un bloc de XAML qui illustre le but de la DataContext, et un exemple de la façon dont un contrôle se réfère à une propriété non dans son propre DataContext

<Window x:Name="myWindow"> <!-- DataContext is set to ClassA --> 
    <StackPanel> <!-- DataContext is set to ClassA --> 

     <!-- DataContext is set to ClassA, so will display ClassA.Name --> 
     <Label Content="{Binding Name}" /> 

     <!-- DataContext is still ClassA, however we are setting it to ClassA.ClassB --> 
     <StackPanel DataContext="{Binding ClassB}"> 

      <!-- DataContext is set to ClassB, so will display ClassB.Name --> 
      <Label Content="{Binding Name}" /> 

      <!-- DataContext is still ClassB, but we are binding to the Window's DataContext.Name which is ClassA.Name --> 
      <Label Content="{Binding ElementName=myWindow, Path=DataContext.Name}" /> 
     </StackPanel> 
    </StackPanel> 
</Window> 

Comme vous pouvez le voir, le DataContext est basé sur toutes les données est derrière l'objet de l'interface utilisateur.

Mise à jour: Je vois cette question si souvent de nouveaux utilisateurs WPF que j'ai développé cette réponse dans un post sur mon blog: What is this “DataContext” you speak of?

+0

Salut! Merci pour la réponse détaillée. Mais. Ce que je n'aime pas dans votre exemple, c'est que vous liez la propriété DataContext elle-même. Très probablement j'extrais StackPanel dans votre exemple dans un contrôle séparé. Cela a du sens si son DataContext est juste une partie isolée de DataContext de son parent, n'est-ce pas? Et puis je ne lierais pas la propriété DataContext de mon contrôle utilisateur, mais aurais plutôt une propriété spéciale avec un nom auto-descriptif. (Je veux dire ce qui est un DataContext pour un contrôle particulier? Que dois-je passer?) Et c'est là que les choses se compliquent. [A suivre] –

+0

Comme je ne lierais pas la propriété DataContext, elle serait prise d'un contrôle parent. Ce qui signifie que je ne suis plus capable de lier des contrôles dans mon contrôle personnalisé sur DataContext, juste parce que je ne sais pas ce qu'il y a dedans (le contrôle ne peut pas contrôler l'enfant et le DataContext qu'il recevra). La solution pourrait être de définir DataContext de l'intérieur pour contrôler (en utilisant une valeur de cette propriété spéciale). [A suivre] –

+0

Mais cela va casser la liaison du contrôle lui-même, car, comme vous l'avez souligné, ayant écrit 'Content = {Binding Name}' on se lie à 'Label.DataContext.Name' et non' Label.Parent. DataContext.Name' comme je m'attendais à le faire. –

1

Dans ce cas particulier, vous pourriez faire:

<Controls:SearchSettings DataContext="{Binding Path=Settings}" Settings="{Binding}" /> 

En supposant que vous voulez tout ce qui peut être contenu des SearchSettings utiliser les paramètres comme il est contexte de données. Fondamentalement, le DataContext affecte l'élément lui-même et tous les descendants qui ne le remplacent pas explicitement.

0

Dans la plupart des cas souhaitez lier à DataContext, dans certains modèles sur ItemsControls, il est le seul moyen de lier à l'élément template par exemple. D'autres liaisons au DataContext sont agréables à écrire et à lire car elles sont concises.

Dans votre exemple, vous pouvez toujours régler le DataContext, il vous suffit de modifier la liaison des paramètres respectivement:

<Controls:SearchSettings DataContext="{Binding Settings}" Settings="{Binding}"/> 
+0

je pensais de cette approche, mais il n'a pas de sens. Pourquoi devrais-je lier deux propriétés, si j'en ai seulement besoin? –

+0

@EugeneStrizhok: Vous n'en avez pas seulement besoin, cela vous permet de lier les paramètres dans les contrôles enfants sans définir de source car vous pouvez maintenant utiliser le DataContext. –

1

De CodeProject par Kishore Gaddam:

DataContext est un des concepts les plus fondamentaux dans la liaison de données. L'objet Binding doit obtenir ses données quelque part, et il existe plusieurs façons de spécifier la source des données, comme l'utilisation de la propriété Source directement dans la liaison, en héritant d'un DataContext de l'élément le plus proche lors de la traversée dans l'arborescence ElementName et RelativeSource propriétés dans l'objet Binding.

Exemple détaillé sur CodeProject: http://www.codeproject.com/Articles/321899/DataContext-in-WPF