Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

INotifyPropertyChanged

Dès que l’on veut faire du binding, on recontre l’interface INotifyPropertyChanged.

Cette interface ne contient qu’un évènement :

event PropertyChangedEventHandler PropertyChanged;

On utilise généralement cet évènement comme ceci :

protected virtual void RaisePropertyChanged(string property)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(property));
}

Sauf que je déconseille formellement de travailler comme ceci. En effet, je refuse de passer le nom de la propriété en chaine de caractères (possibilité de faire des fautes de frappes, pas de refactoring et erreur qu’au moment de l’exécution). Le pire dans le cas d’une faute de frappe ou d’un renomage non répercuté de la propriété c’est que même à l’exception, on n’aura pas d’exception et on risque de perdre du temps à comprendre pourquoi le contrôle bindé n’est pas rafraîchit lorsque la propriété sur laquelle il est bindé change.

D’où l’idée de récupérer le nom de la propriété par code.

Pour cela, on peut utiliser les arbres d’Expressions :

public void RaisePropertyChanged<T>(Expression<Func<T>> exp)
{
    string propertyName = PropertyName.GetPropertyName(exp);
    if (propertyName != null)
        RaisePropertyChanged(propertyName);
}
public static class PropertyName
{

    public static string GetPropertyName(LambdaExpression exp)
    {
        var memberExpression = exp.Body as MemberExpression;
        if (memberExpression != null)
            return memberExpression.Member.Name;
        return null;
    }
}

Du coup, au lieu d’écrire ceci :

RaisePropertyChanged("MyProperty");

On va écrire ceci :

RaisePropertyChanged(() => MyProperty);

C’est déjà une bonne amélioration à mon avis.

Ensuite se pose le problème de la factorisation. En effet, on ne va pas faire ça sur chaque classe. On pourrait se faire une classe de base NotifyPropertyChanged mais C# ne supportant pas le multi-héritage ce n’est pas l’idéal d’où l’idée de préférer l’encapsulation à l’héritage dans ce cas.

public class NotifyPropertyChanged
{
    private Func<PropertyChangedEventHandler> _getRaiseEvent;
    private object _sender;

    public NotifyPropertyChanged(object sender, Func<PropertyChangedEventHandler> getRaiseEvent)
    {
        _getRaiseEvent = getRaiseEvent;
        _sender = sender;
    }




   
public void RaisePropertyChanged(string propName)

    {
        PropertyChangedEventHandler propertyChanged = _getRaiseEvent();
        if (propertyChanged != null)
            propertyChanged(_sender, new PropertyChangedEventArgs(propName));
    }
    public void RaisePropertyChanged<T>(Expression<Func<T>> exp)
    {
        string propertyName = PropertyName.GetPropertyName(exp);
        if (propertyName != null)
            RaisePropertyChanged(propertyName);
    }

}

Ainsi, la classe qui implémentera l’interface INotifyPropertyChanged aura juste à faire ceci :

public event PropertyChangedEventHandler PropertyChanged;


private NotifyPropertyChanged _notifyPropertyChanged;
protected NotifyPropertyChanged NotifyPropertyChanged
{
    get { return _notifyPropertyChanged ?? (_notifyPropertyChanged = new NotifyPropertyChanged(this, () => PropertyChanged)); }
}

Pour l’utiliser, il suffira d’écrire ceci :

NotifyPropertyChanged.RaisePropertyChanged(() => MyProperty);
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié jeudi 26 août 2010 21:17 par Matthieu MEZIL

Classé sous : , ,

Commentaires

# re: INotifyPropertyChanged @ jeudi 26 août 2010 22:39

Je préfère largement les implémentations de Josh Smith &amp; co (plutot que celle la qui vient de Simon non ?) qui vérifie à la compilation en mode debug et évite la vérification en mode Release.

richardc

# re: INotifyPropertyChanged @ jeudi 26 août 2010 23:59

j'aurais mis une constante, en premier lieu, pour la refactorisation.

Graveen

# re: INotifyPropertyChanged @ vendredi 27 août 2010 09:34

On trouve la même chose ici:

http://codingly.com/2008/09/30/inotifypropertychanged-sans-les-strings-ca-vous-dit/

Ainsi qu'une autre manière de faire ici:

http://codingly.com/2008/11/10/introduction-a-monocecil-implementer-inotifypropertychanged/

Personnellement, je trouve que tout ça c'est bien compliqué pour pas grand chose, sachant que:

1) on peut vouloir lancer l'évènement depuis ailleurs que la propriété elle-même

2) certains noms de propriétés tels que "Item[]" sont lancés par les collections, et ça on est bien obligé de le faire à la main

3) on échange "paresse du développeur" contre "coûts de cpu inutiles + complexité d'implémentation". Moi je préfère que le développeur travaille normalement :)

PS: avec CodeFluent, tout ceci est généré automatiquement, c'est encore plus simple :)

smo

# re: INotifyPropertyChanged @ vendredi 27 août 2010 09:58

Tout est dit (sujet évoqué très souvent).

L'essentiel est de penser aux performances car ce sont des choses appelées plus que très souvent au sein de l'application.

Moi, j'ai gardé les noms sous forme de chaînes de caractères ;-) : en mode Debug, ça me pète une exception si la propriété n'existe pas. Point de vue de performance, c'est ce qu'il y a de mieux et de toute façon et quand on renomme une propriété du vue-modèle, on est déjà obligé de penser à remplacer le code XAML où cette propriété est utilisée. Je peux vérifier en plus les RaisePropertyChanged...

kakone

# re: INotifyPropertyChanged @ vendredi 27 août 2010 10:03

@Richard : non ça ne vient pas de Simon (d'ailleurs sinon je ne l'aurais pas blogué) mais il est possible qu'il fasse des choses semblables dans quel cas je serais encore plus conforté dans l'idée de procéder comme j'ai fait. :)

@ Graveen : une constante permet certes de factoriser mais si tu changes le nom de ta propriété et que tu fais un Rename dans VS, il ne modifiera pas le string de ta constante. De même si tu fais une faute de frappe, tu ne t'en apercevras pas.

@ Simon : Le premier lien correspond seulement à la première partie de mon post. Le deuxième est très différent, il sert à éviter de faire les RaisePropertyChanged dans les set.

Je ne pense pas qu'il s'agisse de "paresse du développeur". En effet, ce n'est pas plus rapide pour le développeur de procéder comme

ceci (même s'il peut utiliser l'intellisense dans ce cas). Par contre travailler comme ceci évite des problèmes potentiels. Pour ce qui est du temps cpu que cette opération va engendrer, je pense que dans 99% des applications il est négligeable.

Matthieu MEZIL

# re: INotifyPropertyChanged @ vendredi 27 août 2010 10:11

Voilà, le post de Simon pour ceux qui ne le connaissaient pas :

http://www.simonferquel.net/blog/archive/2009/10/07/inotifypropertychanged.aspx

kakone

# re: INotifyPropertyChanged @ vendredi 27 août 2010 14:10

Merci Stéphane pour le lien mais même réponse que pour l'autre Simon. Ce qui m'a poussé à écrire ce post, ce n'est pas le OnPropertyChanged avec lambda (que j'utilise depuis longtemps) mais la factorisation.

Cela dit, le post de Simon va bien au delà de ce que j'ai fait pour les PropertyChanged  "basiques" des set.

Matthieu MEZIL

# re: INotifyPropertyChanged @ dimanche 29 août 2010 13:25

Soit dit en passant je ne pense pas que le passage d'un évènement en délégué soit possible en VB

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01