2010-12-14 56 views
1

j'ai une classe de voiture comme ceci:Pourquoi la liaison de données ne fonctionne-t-elle pas?

public class car 
{ 
    public String Name {get; private set;} 

    public car(string name) 
    { 
     this.Name = name; 
    } 
} 

J'ai aussi un UserControl:

public partial class CarListItem : UserControl 
{ 
    private Car car; 

    public CarListItem (Car car) 
    { 
     InitializeComponent(); 
     this.car= car; 
    } 

} 

Avec XAML:

<Grid> 
    <Label Content="{Binding Path=car.Name}" Name="lblCarName"/> 
</Grid> 

mais le databinding ne fonctionne pas. Qu'est-ce que je fais mal?

Je souhaite afficher le nom de la voiture sur userControl.

+0

Est-ce que vous définissez réellement un nom n'importe où? –

+0

Quand je crée une voiture, je mets le nom – eflles

Répondre

2

Vous ne devriez pas avoir de préfacer l'expression de liaison avec la voiture ...

<Grid> 
    <Label Content="{Binding Name}" Name="lblCarName"/> 
</Grid> 

... en plus vous devez définir la DataContext de votre UserControl

public partial class CarListItem : UserControl 
{ 
    public CarListItem (Car car) 
    { 
     InitializeComponent(); 

     this.DataContext = car; 
    } 
} 

Aussi mon hypothèse est que vous passez un nom dans le ctor de voiture autre qu'une chaîne vide ou null.

+0

Mauvais entraînement à mettre le 'DataContext' d'un' UserControl' à partir du code (il est écrasé si je fais '

+2

@Dan: Hey Mec, ce type (OP) a besoin de compréhension de base en premier. Il doit apprendre suffisamment pour discuter et même envisager les meilleures pratiques. – decyclone

+0

@Dan Pas d'accord, explication affichée sur votre réponse –

0

Votre liaison est liée au car.Name du datacontext. Dans votre cas, le DataContext est NULL.

Vous avez plusieurs options:

  1. définir le contexte de données au CarListItem exemple
  2. Spécifiez la source de liaison.

La première option est généralement meilleure.

Mieux encore idée serait de définir un DataTemplate pour votre Car, et utiliser une liste de Car s au lieu de explicites CarListItem s:

<DataTemplate DataType="{x:Type local:Car}"> 
    <Grid> 
     <Label Content="{Binding Path=Name}"/> 
    </Grid> 
</DataTemplate> 

Maintenant, vous pouvez utiliser ce modèle comme ItemTemplate dans la liste.

+0

@downvoter: explication est la bienvenue. – Vlad

+0

L'utilisation de la commande 'DataContext' de cette manière est fragile et facilement cassable. Vous devriez le cacher plus profondément dans le modèle du contrôle ou utiliser des alternatives. Ma réponse suggère une solution plus robuste. (Aussi, j'ai voté avant votre modification.) –

+0

Ne vaut pas une downvote si vous me demandez, +1 –

1

Pour qu'une liaison fonctionne, vous devez avoir une valeur dans la propriété DataContext de Control. Il peut également être hérité. Ainsi, les contrôles enfants peuvent également accéder aux parents DataContext s'ils n'en ont pas.

Les propriétés (même pas publiques) ne facilitent pas la liaison, sauf si elles sont utilisées avec Self Binding.

Pour que votre code,

Remplacer

this.car = car; 

Avec

this.DataContext = car; 

et remplacer

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

Avec

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

Hé, c'est quoi le Down Vote ?? Quelque chose ne va pas? – decyclone

+0

L'utilisation de 'DataContext' de la commande de cette façon est fragile et facilement cassée. Vous devriez le cacher plus profondément dans le modèle du contrôle ou utiliser des alternatives. Ma réponse suggère une solution plus robuste. –

+0

Ne vaut pas un downvote si vous me le demandez, +1 –

-1

L'utilisation this.DataContext sera travail, mais il est fragile et horrible et pas une bonne façon de concevoir votre application. Si je devais consommer votre contrôle utilisateur et écrire ce XAML:

<CarListItem DataContext="{Binding MyThing}" /> 

... alors votre commande se brisera, que la Car propriété est définie ou pas correctement. Ce n'est pas très joli.

Une approche plus robuste consiste à marquer votre élément UserControl dans Xaml avec un x:Name, et d'utiliser ElementName dans votre liaison. Alors, votre contrôle ressemble à ceci:

<UserControl x:Name="control" ....... (namespaces/etc here)> 
    <Grid> 
    <Label Content="{Binding Car.Name, ElementName=control}" Name="lblCarName"/> 
    </Grid> 

Maintenant, si vous souhaitez définir DataContext sur le Grid (en utilisant DataContext="{Binding Car, ElementName=control}"), vous pouvez obtenir le bénéfice de datacontext de façon plus robuste. Toutefois, pour que cela fonctionne, vous devez exposer votre champ car en tant que propriété plutôt qu'en tant que champ. Vous devez également implémenter INotifyPropertyChanged afin que l'interface utilisateur se rende compte lorsque vous modifiez la valeur de la propriété, bien que vous puissiez contourner ce problème temporairement en définissant caravant vous appelez InitializeComponent() dans votre constructeur.

+2

Maintenant, je ne comprends pas d'où vous avez obtenu ce tag 'UserControl'. Le 'XAML' en question fait partie de UserControl. J'apprécie vos inquiétudes concernant la robustesse du code, mais votre code est tout simplement confus et trompeur. L'utilisation d'une propriété pour exposer des données d'un contrôle est une mauvaise pratique. Vous devriez toujours utiliser 'Model' pour exposer les données pour la liaison. Mais, ici ce n'est pas le point. Le gars est confondu avec 'DataContext' et les propriétés publiques et non avec les meilleures pratiques. – decyclone

+0

La balise '

+1

Je suis vraiment confus par votre exemple aussi. Voulez-vous dire que lorsque je crée un contrôle utilisateur, la meilleure pratique consiste à nommer l'élément de niveau supérieur et, au sein du contrôle, utiliser ce nom et non le contexte de données comme source de liaison? C'est ce que vous semblez dire, et je n'ai jamais seulement fait cela, je n'ai jamais vu quelqu'un faire ça. Alors pourquoi? –