Microsoft aurait dû implémenter quelque chose de rapide INotifyPropertyChanged
, comme dans les propriétés automatiques, spécifiez simplement {get; set; notify;}
que je pense que cela a beaucoup de sens de le faire. Ou y a-t-il des complications pour le faire?
Pouvons-nous nous-mêmes implémenter quelque chose comme «notifier» dans nos propriétés. Existe-t-il une solution gracieuse pour l'implémentation INotifyPropertyChanged
dans votre classe ou la seule façon de le faire est de déclencher l' PropertyChanged
événement dans chaque propriété.
Sinon, pouvons-nous écrire quelque chose pour générer automatiquement le morceau de code pour déclencher l' PropertyChanged
événement?
Réponses:
Sans utiliser quelque chose comme postsharp, la version minimale que j'utilise utilise quelque chose comme:
Chaque propriété est alors juste quelque chose comme:
ce qui n'est pas énorme; il peut également être utilisé comme classe de base si vous le souhaitez. Le
bool
retour deSetField
vous indique s'il s'agissait d'un no-op, au cas où vous souhaiteriez appliquer une autre logique.ou encore plus simple avec C # 5:
qui peut être appelé comme ceci:
avec lequel le compilateur ajoutera
"Name"
automatiquement.C # 6.0 facilite l'implémentation:
... et maintenant avec C # 7:
la source
[CallerMemberName]
Depuis .Net 4.5, il existe enfin un moyen simple de le faire.
.Net 4.5 introduit un nouvel attribut d'informations sur l'appelant.
C'est probablement une bonne idée d'ajouter également un comparateur à la fonction.
Plus d'exemples ici et ici
Voir également Informations sur l'appelant (C # et Visual Basic)
la source
J'aime vraiment la solution de Marc, mais je pense qu'elle peut être légèrement améliorée pour éviter d'utiliser une "chaîne magique" (qui ne supporte pas le refactoring). Au lieu d'utiliser le nom de la propriété comme chaîne, il est facile d'en faire une expression lambda:
Ajoutez simplement les méthodes suivantes au code de Marc, cela fera l'affaire:
BTW, cela a été inspiré par l' URL mise à jour de
cet article de blogla source
Il y a aussi Fody qui a un complément PropertyChanged , qui vous permet d'écrire ceci:
... et lors de la compilation injecte des notifications de modification de propriété.
la source
"Fody/.*?:",LogCustom2,True
met en surbrillance dans la couleur "Personnalisé 2". Je l'ai fait rose vif donc c'est facile à trouver. Juste tout Fody, c'est la meilleure façon de faire tout ce qui a beaucoup de frappe répétitive.Je pense que les gens devraient accorder un peu plus d'attention à la performance; cela a vraiment un impact sur l'interface utilisateur lorsqu'il y a beaucoup d'objets à lier (pensez à une grille avec plus de 10000 lignes), ou si la valeur de l'objet change fréquemment (application de surveillance en temps réel).
J'ai pris diverses implémentations trouvées ici et ailleurs et j'ai fait une comparaison; consultez la comparaison des performances des implémentations INotifyPropertyChanged .
Voici un aperçu du résultat
la source
J'introduis une classe Bindable dans mon blog à http://timoch.com/blog/2013/08/annoyed-with-inotifypropertychange/ Bindable utilise un dictionnaire comme sac de propriétés. Il est assez facile d'ajouter les surcharges nécessaires à une sous-classe pour gérer son propre champ de sauvegarde à l'aide des paramètres ref.
Le code:
Il peut être utilisé comme ceci:
la source
protected T Get<T>(T defaultValue, [CallerMemberName] string name = null)
et de vérifier égalementif (_properties.ContainsKey(name) && Equals(value, Get<T>(default(T), name)))
Set (pour augmenter et enregistrer lors de la première définition de la valeur par défaut)Je n'ai pas encore eu l'occasion d'essayer moi-même, mais la prochaine fois que je met en place un projet avec une grande exigence pour INotifyPropertyChanged, j'ai l'intention d'écrire un attribut Postsharp qui injectera le code lors de la compilation. Quelque chose comme:
Va devenir:
Je ne sais pas si cela fonctionnera dans la pratique et je dois m'asseoir et l'essayer, mais je ne vois pas pourquoi. Je vais peut-être devoir lui faire accepter certains paramètres pour les situations où plus d'un OnPropertyChanged doit être déclenché (si, par exemple, j'avais une propriété FullName dans la classe ci-dessus)
Actuellement, j'utilise un modèle personnalisé dans Resharper, mais même avec cela, j'en ai marre de toutes mes propriétés étant si longues.
Ah, une recherche rapide sur Google (que j'aurais dû faire avant d'écrire ceci) montre qu'au moins une personne a déjà fait quelque chose comme ça ici . Pas exactement ce que j'avais en tête, mais assez proche pour montrer que la théorie est bonne.
la source
Oui, une meilleure façon existe certainement. C'est ici:
Tutoriel étape par étape rétréci par moi, basé sur cet article utile .
NotifierInterceptor
ProxyCreator
-
Mettez des liaisons dans xaml:
Placez la ligne de code dans le fichier code-derrière MainWindow.xaml.cs comme ceci:
DataContext = ProxyCreator.MakeINotifyPropertyChanged<MainViewModel>();
Attention!!! Toutes les propriétés délimitées doivent être décorées avec un mot-clé virtuel car elles sont utilisées par le proxy du château pour remplacer.
la source
type
,interfaces to apply
,interceptors
.CreateClassProxy<T>
méthode générique . Beaucoup différent ... hmmm, se demandant pourquoi si limité avec la méthode générique. :(Une approche très semblable à AOP consiste à injecter la substance INotifyPropertyChanged sur un objet déjà instancié à la volée. Vous pouvez le faire avec quelque chose comme Castle DynamicProxy. Voici un article qui explique la technique:
Ajout de INotifyPropertyChanged à un objet existant
la source
Regardez ici: http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
Il est écrit en allemand, mais vous pouvez télécharger le ViewModelBase.cs. Tous les commentaires du fichier cs sont écrits en anglais.
Avec cette classe ViewModelBase, il est possible d'implémenter des propriétés pouvant être liées similaires aux propriétés de dépendance bien connues:
la source
Sur la base de la réponse de Thomas qui a été adaptée d'une réponse de Marc, j'ai transformé le code modifié de la propriété réfléchissante en une classe de base:
L'utilisation est la même que la réponse de Thomas, sauf que vous pouvez transmettre des propriétés supplémentaires à notifier. Cela était nécessaire pour gérer les colonnes calculées qui doivent être actualisées dans une grille.
J'ai ceci conduisant une collection d'éléments stockés dans une BindingList exposée via un DataGridView. Cela a éliminé le besoin pour moi d'effectuer des appels Refresh () manuels sur la grille.
la source
Permettez-moi de vous présenter ma propre approche appelée Yappi . Il appartient aux générateurs de classes dérivés du proxy Runtime, ajoutant de nouvelles fonctionnalités à un objet ou un type existant, comme le proxy dynamique de Caste Project.
Il permet d'implémenter INotifyPropertyChanged une fois dans la classe de base, puis de déclarer les classes dérivées dans le style suivant, en prenant toujours en charge INotifyPropertyChanged pour les nouvelles propriétés:
La complexité de la classe dérivée ou de la construction du proxy peut être masquée derrière la ligne suivante:
Et tout le travail d'implémentation INotifyPropertyChanged peut être effectué comme ceci:
Il est entièrement sûr pour le refactoring, n'utilise aucune réflexion après la construction du type et assez rapidement.
la source
TDeclaration
un paramètre de typePropertyImplementation
? Vous pouvez sûrement trouver le type approprié pour appeler (pas callvirt) le getter / setter avec seulementTImplementation
?Toutes ces réponses sont très agréables.
Ma solution utilise les extraits de code pour faire le travail.
Cela utilise l'appel le plus simple à l'événement PropertyChanged.
Enregistrez cet extrait de code et utilisez-le lorsque vous utilisez l'extrait de code "fullprop".
Vous pouvez modifier l'appel à votre guise (pour utiliser les solutions ci-dessus)
la source
Si vous utilisez la dynamique dans .NET 4.5, vous n'avez pas à vous en préoccuper
INotifyPropertyChanged
.si Name est lié à un certain contrôle, cela fonctionne très bien.
la source
Une autre solution combinée utilise StackFrame:
Usage:
la source
get_Foo
méthode en mode Release.J'ai créé une méthode d'extension dans ma bibliothèque de base pour la réutilisation:
Cela fonctionne avec .Net 4.5 en raison de CallerMemberNameAttribute . Si vous souhaitez l'utiliser avec une version antérieure de .Net, vous devez modifier la déclaration de méthode de:
...,[CallerMemberName] string propertyName = "", ...
à...,string propertyName, ...
Usage:
la source
J'ai résolu de cette façon (c'est un peu laborieux, mais c'est sûrement le plus rapide en runtime).
En VB (désolé, mais je pense que ce n'est pas difficile de le traduire en C #), je fais cette substitution avec RE:
avec:
Cette transofrm tout le code comme ceci:
Dans
Et si je veux avoir un code plus lisible, je peux être l'inverse en faisant simplement la substitution suivante:
Avec
Je lance pour remplacer le code IL de la méthode set, mais je ne peux pas écrire beaucoup de code compilé en IL ... Si un jour je l'écris, je vous le dirai!
la source
Je garde ça comme un extrait. C # 6 ajoute une belle syntaxe pour invoquer le gestionnaire.
la source
Voici une version Unity3D ou non CallerMemberName de NotifyPropertyChanged
Ce code vous permet d'écrire des champs de support de propriété comme ceci:
De plus, dans resharper, si vous créez un extrait de modèle / recherche, vous pouvez également automatiser votre flux de travail en convertissant des champs d'accessoires simples en support ci-dessus.
Modèle de recherche:
Remplacer le motif:
la source
J'ai écrit un article qui aide à ce sujet ( https://msdn.microsoft.com/magazine/mt736453 ). Vous pouvez utiliser le package NuSet SolSoft.DataBinding. Ensuite, vous pouvez écrire du code comme ceci:
Avantages:
la source
Bien qu'il existe évidemment de nombreuses façons de le faire, à l'exception des réponses magiques AOP, aucune des réponses ne semble chercher à définir la propriété d'un modèle directement à partir du modèle de vue sans avoir de champ local à référencer.
Le problème est que vous ne pouvez pas référencer une propriété. Cependant, vous pouvez utiliser une action pour définir cette propriété.
Cela peut être utilisé comme l'extrait de code suivant.
Consultez ce dépôt BitBucket pour une implémentation complète de la méthode et quelques façons différentes d'obtenir le même résultat, y compris une méthode qui utilise LINQ et une méthode qui utilise la réflexion. Notez que ces méthodes sont plus lentes en termes de performances.
la source
Vous pouvez également prendre en compte lors de l'implémentation de ces types de propriétés le fait que les INotifyPropertyChang * ed * ing utilisent tous les deux des classes d'arguments d'événement.
Si vous avez un grand nombre de propriétés en cours de définition, le nombre d'instances de classe d'argument d'événement peut être énorme, vous devez envisager de les mettre en cache car elles sont l'une des zones dans lesquelles une explosion de chaîne peut se produire.
Jetez un œil à cette implémentation et expliquez pourquoi elle a été conçue.
Blog de Josh Smiths
la source
Je viens de trouver ActiveSharp - Automatic INotifyPropertyChanged , je ne l'ai pas encore utilisé, mais ça a l'air bien.
Pour citer son site Web ...
Au lieu de cela, écrivez des propriétés comme ceci:
Notez qu'il n'est pas nécessaire d'inclure le nom de la propriété sous forme de chaîne. ActiveSharp le comprend de manière fiable et correcte. Cela fonctionne basé sur le fait que l'implémentation de votre propriété passe le champ de support (_foo) par ref. (ActiveSharp utilise cet appel "par référence" pour identifier le champ de sauvegarde qui a été transmis et à partir du champ, il identifie la propriété).
la source
Une idée par réflexion:
la source
Je me rends compte que cette question a déjà des milliers de réponses, mais aucune ne me semblait tout à fait appropriée. Mon problème est que je ne veux pas de succès de performance et je suis prêt à supporter un peu de verbosité pour cette seule raison. Je ne me soucie pas non plus trop des propriétés automobiles, ce qui m'a conduit à la solution suivante:
En d'autres termes, la solution ci-dessus est pratique si cela ne vous dérange pas:
Avantages
Les inconvénients
Hélas, c'est encore mieux que de faire ça,
Pour chaque propriété, qui devient un cauchemar avec la verbosité supplémentaire ;-(
Remarque, je ne prétends pas que cette solution est meilleure en termes de performances que les autres, mais simplement que c'est une solution viable pour ceux qui n'aiment pas les autres solutions présentées.
la source
Je suis venu avec cette classe de base pour implémenter le modèle observable, fait à peu près ce dont vous avez besoin ( implémenter "automatiquement" l'ensemble et obtenir). J'ai passé une heure en ligne sur ce prototype, donc il n'a pas beaucoup de tests unitaires, mais prouve le concept. Notez qu'il utilise le
Dictionary<string, ObservablePropertyContext>
pour supprimer le besoin de champs privés.Voici l'utilisation
la source
Je suggère d'utiliser ReactiveProperty. C'est la méthode la plus courte sauf Fody.
au lieu
( DOCS )
la source
Une autre idée...
la source
=> voici ma solution avec les fonctionnalités suivantes
la source
Utilisez ceci
}
la source