2010-11-30 18 views
0

Je cherche des conseils sur la façon d'être averti lorsque l'une des nombreuses propriétés change. Par exemple, disons que je veux lier le texte d'un contrôle à une propriété FullAddress dans mon WPF ViewModel que je peux calculer à la volée chaque fois qu'un des changements de propriétés, tels que StreetNumber, StreetName, Suburb, PostCode, etc.Génération d'une chaîne dans le code lorsque l'un des groupes de propriétés change

Je pense que j'ai besoin de lier mon contrôle d'affichage à la propriété FullAddress, mais comment est-ce que je le mets automatiquement à jour quand l'une des propriétés dépendantes change? Puis-je lier le codebehind de la propriété à plusieurs autres propriétés sur le même ViewModel? Si c'est le cas, comment? Y a-t-il un meilleur moyen?

Répondre

1

Je pense que votre seule option ici est d'avoir des objets de votre classe abonner à leurs propres événements INPC et modifier leurs propriétés dépendantes automatiquement. Le flux de travail irait comme ceci:

  1. objet est créé
  2. est abonnée objet à sa propre INPC
  3. Une propriété dépendante est modifiée
  4. L'abonnement INPC détecte qu'une propriété à charge pour FullAddress a changé, et met à jour la valeur FullAddress
  5. le feu setter FullAddress son propre événement INPC
  6. WPF détecte que FullAddress a ch ANGed et met à jour l'interface utilisateur

Mise à jour: Exemple de code

class NotificationExample : INotifyPropertyChanged 
{ 
    private string firstName; 
    private string lastName; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public string FirstName 
    { 
     get { return this.firstName; } 

     set 
     { 
      this.firstName = value; 
      this.OnPropertyChanged("FirstName"); 
     } 
    } 

    public string LastName 
    { 
     get { return this.lastName; } 

     set 
     { 
      this.lastName = value; 
      this.OnPropertyChanged("LastName"); 
     } 
    } 

    public string FullName 
    { 
     get { return string.Format("{0} {1}", this.firstName, this.lastName); } 
    } 

    public NotificationExample() 
    { 
     this.PropertyChanged += this.NotifyIfFullNameChanged; 
    } 

    private void OnPropertyChanged(string propertyName) 
    { 
     var handler = this.PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    private void NotifyIfFullNameChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == "FirstName" || e.PropertyName == "LastName") 
     { 
      this.OnPropertyChanged("FullName"); 
     } 
    } 
} 
+0

Merci Jon, une autre réponse rapide. Cela me prend le temps de me mettre à la tête. Je comprends un peu mais à l'étape 4, comment l'abonnement INPC sait-il quelles propriétés sont dépendantes de la propriété FullAddress?Je présume que par l'objet vous voulez dire l'instance de la classe qui contient les propriétés FullAddress et dépendantes, l'objet lui-même appelle-t-il PropertyChanged sur l'ensemble de l'objet par opposition à une seule propriété? – TripleAntigen

+0

L'abonné INPC serait une méthode privée dans votre classe. Il "sait" de quoi dépend FullAddress car vous le connaissez (si e.PropertyName == "StreetAddress" etc). L'objet est ce que tu as dit. PropertyChanged est toujours appelé sur une propriété spécifique, vous ne pouvez pas l'appeler "sur l'objet entier". Pour que cela fonctionne, FullAddress et ses propriétés dépendantes doivent appeler PropertyChanged depuis leur setter. – Jon

+0

Merci! Je suis presque là ... donc si je comprends bien, quand vous dites 'Objet souscrit à son propre INPC' voulez-vous dire que dans chaque propriété dépend de FullAddress, j'appelle PropertyChanged pour cette propriété mais j'appelle aussi OnPropertyChanged pour le Propriété FullAddress comme indiqué les exemples de code? Ou existe-t-il un moyen pour un objet d'être averti par le backend de propriété de dépendance WPF que quelque chose dans l'objet a changé? Désolé, je ne suis pas sûr du lien entre la méthode privée et l'abonnement INPC. – TripleAntigen

1

En supposant que votre classe implémente INotifyPropertyChanged, vous pouvez notifier à l'intérieur de n'importe quel ensemble de propriétés. par exemple

#region Implementation of INotifyPropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      Address.BeginEdit(); 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 


    #endregion 

    public string FirstLine 
    { 
     get { return firstLine; } 
     set 
     { 
      firstLine = value; 
      OnPropertyChanged("FirstLine"); 
      OnPropertyChanged("FullAddress"); 
     } 
    } 


    public string SecondLine 
    { 
     get { return secondLine; } 
     set 
     { 
      secondLine= value; 
      OnPropertyChanged("SecondLine"); 
      OnPropertyChanged("FullAddress"); 
     } 
    } 

    public string FullAddress 
    { 
     get { return firstLine + secondLine; } 
    } 

+0

David Merci pour la réponse très rapide, et pour le code, cela fait toutes sortes de sens. Très appréciée! – TripleAntigen

1

essayer quelque chose comme ceci:

public class Address : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private string address1; 
    public string Address1 
    { 
     get { return address1; } 
     set 
     { 
      address1 = value; 
      OnPropertyChanged("Address1"); 
      OnPropertyChanged("FullAddress"); 
     } 
    } 

    private string address2; 
    public string Address2 
    { 
     get { return address2; } 
     set 
     { 
      address2 = value; 
      OnPropertyChanged("Address2"); 
      OnPropertyChanged("FullAddress"); 
     } 
    } 

    private string town; 
    public string Town 
    { 
     get { return town; } 
     set 
     { 
      town = value; 
      OnPropertyChanged("Town"); 
      OnPropertyChanged("FullAddress"); 
     } 
    } 

    public string FullAddress 
    { 
     get { return string.Format("{0}, {1}, {2}", address1, address2, town); } 
    } 

    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

Dean Je vous remercie aussi pour la réponse rapide, les grands esprits se ressemblent apparemment, je suis impressionné par l'accord entre le vôtre et la première réponse. Je vais étudier ce code. – TripleAntigen

+0

Je pense que nous avons posté à peu près en même temps, et ils sont tous les deux corrects –

+0

Dommage, je ne semble pas être en mesure de voter utile à tous les messages encore, désolé c'est ma première fois sur StackOverflow. – TripleAntigen

1

Vous pouvez utiliser MultiBinding et ne pas utiliser la propriété FullAddress du tout
EDIT:
Si vous ne devez afficher l'adresse complète que vous pouvez utiliser StringFormat

<TextBlock> 
    <TextBlock.Text> 
     <MultiBinding StringFormat="{}{0}, {1}"> 
      <Binding Path="City"/> 
      <Binding Path="Street"/> 
     </MultiBinding> 
    </TextBlock.Text> 
</TextBlock> 

Si vous souhaitez autoriser les utilisateurs éditer toute chaîne d'adresse, puis le diviser en plusieurs parties, alors vous devez implémenter IMultiValueConverter Interface

+0

Merci Alpha-souris J'ai lu d'autres articles sur MultiBinding avant de demander, mais j'ai le sentiment que je devrais encore invoquer un convertisseur de valeur pour construire le FullAddress à partir de ses composants, non? Ou éventuellement un attribut de format de chaîne s'il ne nécessite pas beaucoup de formatage? – TripleAntigen

+0

@TripleAntigen: j'ai édité ma réponse. Oui, vous aurez besoin de l'un ou l'autre convertisseur de chaîne de format, mais vous n'aurez pas besoin d'écouter les changements de propriété vous-même: le mécanisme de liaison le fera pour vous –

+0

Informations brillantes, merci beaucoup pour votre temps alpha. – TripleAntigen