2009-07-17 8 views
8

J'ai créé un UserControl destiné à être mis à jour toutes les quelques secondes avec les données d'un port série. Ce UserControl devrait être très simple, composé d'une étiquette pour un nom de champ et d'une autre étiquette contenant la valeur du champ. Je dis que devrait être être simple, mais cela ne fonctionne pas. Il ne se met pas du tout à jour et n'affiche même pas le nom du champ.Problème wpf lors de l'utilisation des propriétés de dépendance dans UserControl

Voici le code:

public partial class LabeledField : UserControl { 

    public LabeledField() { 
     InitializeComponent(); 
    } 

    public string fieldName { 
     get { return fieldNameLabel.Content.ToString(); } 
     set { fieldNameLabel.Content = value; } 
    } 

    public string fieldValue { 
     get { return (string)GetValue(fieldValueProperty); } 
     set { SetValue(fieldValueProperty, value); } 
    } 

    public static readonly DependencyProperty fieldValueProperty = 
     DependencyProperty.Register(
      "fieldValue", 
      typeof(string), 
      typeof(LabeledField), 
      new FrameworkPropertyMetadata(
       "No Data" 
      ) 
     ) 
    ; 
} 

Voici le XAML:

<UserControl x:Class="DAS1.LabeledField" Name="LF" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
<StackPanel Orientation="Horizontal"> 
    <Label Width="100" Height="30" Background="Gray" Name="fieldNameLabel" /> 
    <Label Width="100" Height="30" Background="Silver" Name="fieldValueLabel" Content="{Binding fieldValue}" /> 
</StackPanel> 

Et voici le XAML pour la fenêtre qui fait référence à la UserControl. Tout d'abord l'en-tête:

<Window x:Class="DAS1.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" 
xmlns:me="clr-namespace:DAS1" 
Title="Window1" Height="580" Width="780"> 

Puis le UserControl lui-même:

<me:LabeledField fieldName="Test" Width="200" Height="30" fieldValue="{Binding businessObjectField}"/> 

Si je savais une question plus précise à poser, je - mais quelqu'un peut me dire pourquoi cela ne fonctionne pas?

Répondre

9

Il s'avère que dans le code XAML pour le contrôle utilisateur, la liaison a été spécifiée de manière incorrecte.

l'origine, il était:

<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding fieldValue}" /> 

Mais je n'avais pas précisé l'élément auquel appartient fieldValue. Il devrait être (en supposant mon contrôle utilisateur est nommé « LF »:

<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding ElementName=LF, Path=fieldValue}" /> 
+0

Enfin! Passé 5 heures à figurer choses dehors. TNX! – zdrsh

+0

Merci! Une solution simple était exactement ce dont j'avais besoin. – dex3703

5

Si vous souhaitez lier aux propriétés du contrôle, vous devez le spécifier dans la liaison. Les liaisons sont évaluées par rapport à DataContext si leur source n'est pas explicitement spécifiée, donc votre liaison ne se lie pas à votre contrôle, mais au contexte hérité (qui manque probablement la propriété à laquelle vous vous liez). Qu'est-ce que vous avez besoin est:

<Label Width="100" Height="30" Name="fieldValueLabel" 
     Content="{Binding Path=fieldValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DAS1.LabeledField}}}" /> 
4

Vous avez vraiment pas besoin d'une propriété de dépendance de votre contrôle utilisateur, en fait, vous devez vous efforcer de garder les contrôles utilisateur sans rien de spécial dans le code-behind, les contrôles personnalisés doivent être utilisés pour cette.

Vous devez définir votre UserControl comme celui-ci (sans code derrière):

<UserControl x:Class="DAS1.LabeledField" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <StackPanel Orientation="Horizontal"> 
     <Label Width="100" Height="30" Name="fieldNameLabel" Content="{Binding fieldName}" /> 
     <Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding field}" /> 
</StackPanel> 

Ensuite, assurez-vous que votre objet métier implémente INotifyPropertyChanged, parce que vous ne pouvez pas mettre à jour de votre objet métier efficacement sans le modifier au moins ce beaucoup. Le fieldName est juste un exemple comment vous pouvez lier automatiquement le nom affiché sur l'étiquette à une propriété de votre objet métier. Ensuite, assurez-vous simplement que le DataContext de votre UserControl est votre objet métier.

Comment cela fonctionnera-t-il? La propriété Label.Content est DependencyProperty et prend en charge la liaison elle-même. Votre objet métier implémente INotifyPropertyChanged et prend donc en charge les mises à jour à la liaison - sans cela, le système de liaison n'est pas averti lorsque la valeur de votre champ change, même si vous l'avez lié à DependencyProperty à une extrémité.

Et si vous souhaitez réutiliser ce contrôle utilisateur ailleurs, placez simplement une instance de votre objet métier souhaitée dans le DataContext du contrôle LabeledField souhaité. La liaison se connectera à partir du DataContext.

+0

J'aime votre solution, car il est simple j'ai essayé de le mettre en œuvre mais sans succès Le XAML pour la LabeledField ressemble exactement comme vous.. Le code derrière maintenant ne contient qu'un constructeur qui appelle "InitializeComponents()", qui est la valeur par défaut Le XAML de Window1 ressemble à ceci: "" Il me donne des erreurs qui disent "La propriété 'fieldName'/'fieldValue' n'a pas été trouvé dans le type 'LabeledField'". D'autres suggestions? – Klay

+0

Vous devriez avoir une entreprise objet qui expose les propriétés "field" et "fieldName" et définit cet objet en tant que DataContext de LabeledFie contrôle ld. Par exemple "public class BusinessObject {public string nom_fichier {get {return" Texte ";}} champ public int {get {return 30;}}}" dans le code, puis dans xaml: " –

+3

J'apprécie cette solution mais cette solution n'est pas bien adaptée aux contrôles utilisateur qui sont conçus pour être réutilisés/consommés plusieurs fois dans la même interface. Chaque instance va utiliser les mêmes liaisons que si le dev voulait pousser des données basées sur des chaînes différentes dans chaque instance du contrôle utilisateur donné? Cette solution en théorie ne devrait pas fonctionner – IbrarMumtaz

Questions connexes