2010-08-18 3 views
1

j'ai un UserControl avec une propriété Template que j'ai mis en place comme DependencyProperty:WPF, ne peut lier une propriété parce qu'il dit que ce n'est pas un DependencyProperty, mais j'enregistré il

public partial class TemplateDetail : UserControl 
{ 
    public static readonly DependencyProperty _templateProperty = 
     DependencyProperty.Register(
      "Template", 
      typeof(Template), 
      typeof(TemplateDetail) 
     ); 

    public TemplateDetail() 
    { 
     InitializeComponent(); 
     Template = new Template(); 
     DataContext = Template; 
    } 

    public Template Template 
    { 
     get 
     { 
      return (Template)GetValue(_templateProperty); 
     } 
     set { SetValue(_templateProperty, value); } 
    } 
} 

Je suis en train d'utiliser cette UserControl dans le XAML pour un Window, SaveTemplateDialog, et je suis en train de définir sa propriété Template à la propriété Template dans ma classe SaveTemplateDialog:

<local:TemplateDetail HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
         MinWidth="100" Template="{Binding}" 
         Width="{Binding ElementName=Scroller, Path=ViewportWidth}"/> 

Le DataContext dans SaveTemplateDialog est défini sur sa propriété Template, qui est également une propriété de dépendance. Cependant, pour le XAML ci-dessus, Template="{Binding}" est souligné en bleu dans Visual Studio et il dit:

A « Reliure » ne peut pas être mis sur la propriété « modèle » de type « TemplateDetail ». Une 'liaison' ne peut être définie que sur un DependencyProperty d'un DependencyObject.

Effectivement, quand je charge mon application, le contenu des Template que TemplateDetail tente à afficher est vide, quand je sais qu'il ya des valeurs qu'il contient. Pourquoi donne-t-il ce message si j'ai enregistré TemplateDetail.Template en tant que propriété de dépendance?

Modifier: maintenant je suis assez confus. Dans ma fenêtre SaveTemplateDialog, je fais ce qui suit pour transmettre le modèle à la TemplateDetailUserControl:

<local:TemplateDetail HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
         TemplateData="{Binding Path=NewTemplate, Mode=OneWay}" 
         Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3"/> 

Je sais Path=NewTemplate est d'obtenir les bonnes données, parce que j'ai aussi ce XAML dans SaveTemplateDialog, qui montre la valeur I peut s'y attendre dans la propriété MyType de NewTemplate:

<TextBlock Text="{Binding Path=NewTemplate.MyType}" /> 

ce TextBlock montre ce que je pense. Cependant, apparemment les bonnes données n'obtiennent pas à TemplateDetail ou je ne suis pas lié correctement là, parce que je ne peux pas obtenir la même propriété MyType (ou les autres propriétés Template) pour apparaître dans TemplateDetail. En TemplateDetail:

<TextBlock Text="{Binding Path=TemplateData.MyType}" Grid.Row="2" Grid.Column="2" 
      HorizontalAlignment="Stretch" Width="200"/> 

Et voici la classe TemplateDetail comme il est maintenant:

public partial class TemplateDetail : MainWindowUserControl 
{ 
    public static readonly DependencyProperty TemplateDataProperty = 
     DependencyProperty.Register(
      "TemplateData", 
      typeof(Template), 
      typeof(TemplateDetail), 
      new PropertyMetadata(
       new Template("Default Template", null) 
      ) 
     ); 

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

    public Template TemplateData 
    { 
     get 
     { 
      return (Template)GetValue(TemplateDataProperty); 
     } 
     set { SetValue(TemplateDataProperty, value); } 
    } 
} 
+1

Je ne suis pas sûr de savoir si Template est un mot réservé ici. Avez-vous essayé une propriété de dépendance nommée différemment? – Robaticus

+0

@Robaticus: J'ai renommé la propriété 'TemplateDetail.Template' en' TemplateData'; qui s'est débarrassé de la ligne bleue et d'avertissement sur la liaison. Je ne vois toujours pas les données du modèle lorsque j'utilise mon application, mais c'est probablement un problème différent. Merci! Vous devriez ajouter votre commentaire en guise de réponse. –

Répondre

3

Vous devez modifier le nom de votre DependencyProperty à l'utilisation de la convention standard comme PropertyNameProperty au lieu de nommer comme un champ. Lorsque vous définissez quelque chose en XAML, il appelle SetValue et attend que la propriété soit nommée en utilisant le nom de la chaîne ("Template" ici) suivi de "Property".

MISE À JOUR pour la deuxième question:

Lorsque vous définissez DataContext = this dans votre constructeur TemplateDetail qui est à l'origine de la source de votre chemin = NewTemplate liaison à modifier de la DataContext héritée au contrôle TemplateDetail lui-même. Vous devriez voir une erreur dans votre fenêtre de sortie que la propriété NewTemplate ne peut pas être trouvée sur l'objet de type TemplateDetail.Au lieu de réinitialiser le DataContext de UserControl lui-même, je donnerai à la place au Panel de mise en forme racine dans mon XAML UserControl un x: Name et définirai LayoutRoot.DataContext = this dans le constructeur à la place.

+0

Hm. Je l'ai fait, en référençant la page de MSDN sur les propriétés de dépendance, mais mon application n'affichait pas les données dans la propriété après avoir défini la propriété en XAML. Mon application a toujours montré la valeur initiale, définie par le constructeur, de la propriété de dépendance. J'ai essayé de passer des propriétés de dépendance à ce que ma classe implémente 'INotifyPropertyChanged', mais maintenant il est de retour à dire" A 'Binding' ne peut pas être défini ... ". –

+1

C'est un problème distinct. Vous ne devez pas définir de valeurs par défaut pour les points de distribution dans le constructeur de votre contrôle. Au lieu de cela, passez une PropertyMetadata dans Register avec votre valeur par défaut (pour les types de valeur) ou appliquez-la via un Style par défaut. –

+0

@John: Je l'ai modifié pour que la valeur par défaut/initiale de ma propriété de dépendance soit définie dans l'appel 'Register'. J'ai mis à jour ma question avec mon problème actuel. Merci! –

2

Assurez-vous que Modèle n'est pas un mot réservé qui provoque la confusion du processeur XAML. Essayez un mot différent.

(affiché comme réponse par Sarah Vessel's suggestion).

0

Je pense que quelque chose n'est pas mis à jour comme il se doit. Je trouve que si je faisais ce qui suit dans ma NewTemplate propriété dans ma fenêtre SaveTemplateDialog, alors mon TemplateDetailUserControl est correctement rempli toutes les données que je pense:

public Template NewTemplate 
{ 
    get 
    { 
     return (Template)GetValue(NewTemplateProperty); 
    } 
    set 
    { 
     SetValue(NewTemplateProperty, value); 

     // The magic line, explicitly setting TemplateData property on 
     // the TemplateDetails UserControl: 
     uct_templateDetails.TemplateData = value; 
    } 
} 

Cela me porte à croire juste avoir les éléments suivants dans SaveTemplateDialog ne suffit pas de » XAML d'envoyer la nouvelle instance à chaque fois TemplateDetailsNewTemplate est mis à jour:

<local:TemplateDetail HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
         TemplateData="{Binding Path=NewTemplate}" Grid.Row="2" 
         Grid.Column="1" Grid.ColumnSpan="3" 
         x:Name="uct_templateDetails"/> 

J'aimerais pour quelqu'un de signaler ce que je fais mal ici parce qu'il ne semble pas que je devrais avoir à ex Précisez uct_templateDetails.TemplateData = value; chaque fois que SaveTemplateDialog.NewTemplate est modifié. Je pensais que c'était le point d'une propriété de dépendance, que sa mise à jour ferait que les choses qui l'utilisent obtiendraient la valeur mise à jour.

+1

Vous ne devez jamais placer de code autre que l'appel de SetValue dans votre propriété d'encapsuleur DP: utilisez plutôt un callback de propriété modifié. Tous les appels de XAML ignorent le wrapper et appellent SetValue directement, sans mentionner que n'importe qui peut appeler GetValue/SetValue à partir du code. –

Questions connexes