2010-08-12 3 views
2

En général, dans le poseur de propriété d'un objet on peut vouloir soulever un événement PropertyChanged tel queWPF événements PropertyChanged excessives

public event PropertyChangedEventHandler PropertyChanged; 
    protected void Notify(string property) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(property)); 
     } 
    } 

    public string UserNote 
    { 
     get { return _userNote; } 
     set 
     { 
      _userNote = value; 
      Notify("UserNote"); 
     } 
    } 

Dans notre base de code existant, je vois des cas où PropertyChangedEventArgs est envoyé nulle pour indique que toutes les propriétés de l'objet ont changé. Cela semble inefficace et semble conduire à beaucoup plus d'événements déclenchés que nécessaire. Il semble également causer des problèmes où les objets se mettent à jour les uns les autres de façon circulaire.

Est-ce toujours une bonne pratique?

Un commentaire dans le code tente de justifier ...

//The purpose of this method is to wire up clients of NotificationBase that are also 
//NotificationBases to *their* clients. Consider the following classes:  
     public class ClassA : NotificationBase 
     { 
      public int Foo 
      { 
       get { return 123; } 
       set { Notify("Foo"); } 
      } 
     } 

     public class ClassB : NotificationBase 
     { 
      ClassA A = new ClassA(); 
      public ClassB() 
      { 
       A.PropertyChanged += AllChanged; 
      } 
      public void SetFoo() 
      { 
       A.Foo = 456; 
      } 
     } 

     public class ClassC 
     { 
      ClassB B = new ClassB(); 
      public ClassC() 
      { 
       B.PropertyChanged += delegate { dosomething(); }; 
       B.SetFoo(); // causes "dosomething" above to be called 
      } 
     } 

     /// ClassB.SetFoo calls ClassA.Foo's setter, which calls ClassA.Notify("Foo"). 
     /// The event registration in ClassB's ctor causes ClassB.AllChanged to be called, which calls 
     /// ClassB.Notify(null) - implying that ALL of ClassB's properties have changed. 
     /// The event registration in ClassC's ctor causes the "dosomething" delegate to be called. 
     /// So a Notify in ClassA is routed to ClassC via ClassB's PropertyChanged event. 

     protected void AllChanged(Object sender, PropertyChangedEventArgs e) 
     { 
      Notify(null); 
     } 

Toute pensée très appréciée.

Cordialement, Fzzy

+0

Voulez-vous des informations sur les propriétés standard ou DependencyProperty? –

+0

Sans aller trop loin, ce code a l'air un peu effrayant et le gros commentaire essayant de décrire l'intention de la méthode me semble être une grosse "odeur". Qu'est-ce que vous essayez réellement de faire? Le consommateur de l'événement Notification doit décider de ce qu'il doit faire lorsqu'il est informé d'un changement de propriété. –

+0

Un exemple est où nous avons un objet Fixture qui a une propriété FixtureStatus. Il existe un certain nombre d'autres propriétés qui dépendent de FixtureStatus pour déterminer leurs valeurs. Je pense que la méthode Notify devrait être appelée avec le nom de chacune de ces propriétés dépendantes plutôt qu'une notification à tous. Le code commence à être un peu compliqué avec un appel Notify pour chaque propriété dépendante. – user418689

Répondre

3

Ceci est en fait un problème avec la conception (ou sa documentation) de PropertyChangedEventArgs. La définition de PropertyName sur null signifie que "toutes les propriétés de cet objet ont été modifiées". Mais sauf si la classe est scellée, ou si vous utilisez la réflexion, vous ne pouvez pas savoir que toutes les propriétés ont été modifiées. Tout ce que vous pouvez dire, c'est que toutes les propriétés de la classe de base de l'objet ont changé. Ceci est une raison suffisante pour ne pas utiliser cette convention particulière, dans mon livre, sauf dans le très petit nombre de cas où je crée des classes scellées qui implémentent la notification de changement de propriété. En pratique, ce que vous essayez vraiment de faire, c'est de déclencher un événement qui dit aux auditeurs "tout un tas de propriétés sur cet objet ont changé, mais je ne vais pas prendre la peine de vous en parler. un par un.«Quand vous dites:.

Je vois des cas où PropertyChangedEventArgs est envoyé nulle afin d'indiquer que toutes les propriétés de l'objet ont changé Cela semble inefficace et semble conduire à être déclenché que nécessaire bien d'autres événements.

... l'intention réelle est exactement le contraire. Si une méthode modifie les Foo, Bar, Baz et Bat propriétés sur un objet, et l'objet n'a que quatre ou cinq propriétés, ce qui soulève un événement est probablement mieux que d'élever quatre. D'un autre côté, si l'objet a soixante propriétés, quatre événements est probablement préférable de faire en sorte que chacun des auditeurs de l'objet - même ceux qui ne regardent pas ces quatre propriétés - fasse tout ce qu'il fait quand les propriétés dont il se soucie changent, parce que ces propriétés ne le font pas.

Le problème est que le système de notification de changement de propriété, tel qu'il est conçu, n'est pas un outil assez fin pour chaque travail. Il est conçu pour être complètement générique et n'a aucune connaissance d'un domaine d'application particulier.

Et il me semble que c'est ce qui manque à votre conception: la connaissance du domaine d'application. Dans votre deuxième exemple, si un objet Fixture a (par exemple) dix propriétés qui dépendent de la valeur de FixtureStatus, l'augmentation de dix événements de changement de propriété peut sembler un peu excessive. Peut etre c'est. Peut-être que l'objet devrait déclencher un événement FixtureStatusChanged à la place. Ensuite, les classes connaissant votre domaine d'application peuvent écouter cet événement et ignorer l'événement PropertyChanged. (Vous continuez à déclencher l'événement PropertyChanged sur les autres propriétés, de sorte que les objets ne connaissent pas et savent ce qu'un événement FixtureStatusChanged peut rester à jour - c'est-à-dire s'il est toujours nécessaire que votre classe implémente INotifyPropertyChanged une fois que vous avez implémenté FixtureStatusChanged Un commentaire secondaire: La plupart des classes de l'univers C#, si elles implémentent une méthode qui déclenche l'événement Foo, appellent cette méthode OnFoo. C'est une convention importante: elle rend explicite la relation entre la méthode et l'événement, et fait que le code qui appelle la méthode soulève un événement facile à reconnaître. Notify est un nom faible pour une méthode en général - notifier qui? de quoi? - et dans ce cas, il obscurcit quelque chose qui devrait être rendu explicite. La notification de modification de propriété est assez délicate sans que votre convention de dénomination cache le fait que cela se produit.

0

Ignorant les autres choses, je dirais que le Notify(null) seul est une mauvaise pratique. Ce n'est pas clair en soi ce que cela signifie, et pour un développeur travaillant le code 5 ans plus tard, supposerait probablement que cela signifiait autre chose, à moins qu'ils ne se produisent sur les commentaires.

0

J'ai rencontré des situations où les propriétés calculées (sans setters) doivent déclencher PropertyChangeNotification quand une autre propriété est définie via un setter.

par exemple

numéro double {get {return num;} { mis num = valeur; OnPropertyChanged ("Nombre"); OnPropertyChanged ("TwiceNumber"); }}

à double TwiceNumber {get {return _num * 2.0;}}

En règle générale, je fais seulement avec obtenir des propriétés seulement et je ne vois pas pourquoi dans ce cas, une propriété tirer une notification de changement de l'autre est mauvais. Mais je pense que si je le fais pour tout autre cas, je ne sais probablement pas ce que je fais!

Questions connexes