Quelqu'un sait-il pourquoi ce code ne fonctionne pas:
public class CollectionViewModel : ViewModelBase {
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
set
{
_contentList = value;
RaisePropertyChanged("ContentList");
//I want to be notified here when something changes..?
//debugger doesn't stop here when IsRowChecked is toggled
}
}
}
public class EntityViewModel : ViewModelBase
{
private bool _isRowChecked;
public bool IsRowChecked
{
get { return _isRowChecked; }
set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
}
}
ViewModelBase
contient tout pour RaisePropertyChanged
etc. et il fonctionne pour tout le reste sauf ce problème.
c#
observablecollection
inotifypropertychanged
Joseph jun. Melettukunnel
la source
la source
Réponses:
La méthode Set de ContentList ne sera pas appelée lorsque vous modifiez une valeur à l'intérieur de la collection, à la place, vous devriez rechercher le déclenchement de l' événement CollectionChanged .
D'accord, c'est deux fois aujourd'hui que j'ai été mordu par la documentation MSDN qui était fausse. Dans le lien que je vous ai donné, il est dit:
Mais en fait, il ne se déclenche pas lorsqu'un élément est modifié. Je suppose que vous aurez besoin d'une méthode plus bruteforce alors:
Si vous en avez beaucoup besoin, vous voudrez peut-être sous-classer le vôtre
ObservableCollection
qui déclenche l'CollectionChanged
événement lorsqu'un membre déclenchePropertyChanged
automatiquement son événement (comme il le dit dans la documentation ...)la source
changed
? Cela pourrait signifier qu'une propriété de l'un des éléments de la collection a changé (c'est ainsi que je pense que vous l'interprétez) ou cela pourrait signifier qu'un des éléments de la collection a été modifié en le remplaçant par une instance différente ( c'est mon interprétation). Pas totalement convaincu cependant - devra examiner cela plus en détail._contentList.Clear()
? Personne ne se désabonneraPropertyChanged
!ContentCollectionChanged
ne gère que Ajouter / Supprimer et non Remplacer / Réinitialiser. Je vais essayer de modifier et de corriger le message. La façon dont Simon le fait dans sa réponse est correcte.Voici une classe drop-in qui sous-classe ObservableCollection et déclenche en fait une action Reset lorsqu'une propriété d'un élément de liste change. Il applique tous les éléments à mettre en œuvre
INotifyPropertyChanged
.L'avantage ici est que vous pouvez lier des données à cette classe et toutes vos liaisons seront mises à jour avec les modifications apportées aux propriétés de vos éléments.
la source
NotifyCollectionChangedAction.Replace
n'est pas une bonne idée, car alors vous ne pouvez pas faire la distinction entre un élément en fait remplacé ou un événement causé par un changement d'élément. Cela va beaucoup mieux quand vous définissezpublic event PropertyChangedEventHandler CollectionItemChanged;
et puisItemPropertyChanged
faitesthis.CollectionItemChanged?.Invoke(sender, e);
J'ai mis au point ce que j'espère être une solution assez robuste, y compris certaines des techniques dans d'autres réponses. C'est une nouvelle classe dérivée de
ObservableCollection<>
, que j'appelleFullyObservableCollection<>
Il présente les caractéristiques suivantes:
ItemPropertyChanged
. J'ai délibérément gardé cela séparé de l'existantCollectionChanged
:ItemPropertyChangedEventArgs
qui l'accompagne: l'originalPropertyChangedEventArgs
et l'index dans la collection.ObservableCollection<>
.ObservableCollection<>.Clear()
), évitant ainsi une éventuelle fuite de mémoire.OnCollectionChanged()
, plutôt qu'un abonnement plus gourmand en ressources à l'CollectionChanged
événement.Code
Le
.cs
dossier complet suit. Notez que quelques fonctionnalités de C # 6 ont été utilisées, mais il devrait être assez simple de le rétroporter:Tests NUnit
Pour que vous puissiez vérifier les modifications que vous pourriez apporter (et voir ce que j'ai testé en premier lieu!), J'ai également inclus ma classe de test NUnit. De toute évidence, le code suivant n'est pas nécessaire uniquement pour l'utiliser
FullyObservableCollection<T>
dans votre projet.NB La classe de test utilise
BindableBase
de PRISM pour l'implémentationINotifyPropertyChanged
. Il n'y a aucune dépendance sur PRISM du code principal.la source
ListView
répondra auxCollectionChanged
événements parce qu'il les connaît.ItemPropertyChanged
est un ajout non standard, vous devez donc lui apprendre à ce sujet. En tant que solution rapide et sale, vous pouvez essayer de tirer tout l'CollectionChanged
événement ainsi que (ou même au lieu de)ItemPropertyChanged
dansOnItemPropertyChanged()
. Je les ai gardés séparés pour les raisons indiquées dans la réponse, mais pour votre cas d'utilisation, cela pourrait simplement faire ce dont vous avez besoin.Cela utilise les idées ci-dessus mais en fait une collection dérivée `` plus sensible '':
la source
ObservableCollection ne propagera pas les modifications d'éléments individuels en tant qu'événements CollectionChanged. Vous devrez soit vous abonner à chaque événement et le transférer manuellement, soit consulter la classe BindingList [T] , qui le fera pour vous.
la source
Ajouté à l'événement TruelyObservableCollection "ItemPropertyChanged":
la source
J'ai utilisé la réponse de Jack Kenyons pour implémenter mon propre OC, mais j'aimerais souligner un changement que j'ai dû faire pour que cela fonctionne. Au lieu de:
J'ai utilisé ceci:
Il semble que le "e.NewItems" produit null si l'action est .Remove.
la source
Je viens d'ajouter mes 2 cents sur ce sujet. Senti que TrulyObservableCollection nécessite les deux autres constructeurs trouvés avec ObservableCollection:
la source
Je sais que je suis trop tard pour cette fête, mais peut-être - cela aidera quelqu'un ...
Ici vous pouvez trouver mon implémentation d'ObservableCollectionEx. Il a quelques caractéristiques:
Bien sûr, tous les commentaires sont appréciés;)
la source
Si je connais ObservableCollection, créez un événement uniquement lorsque nous ajoutons / supprimons ou déplaçons des éléments dans notre collection. Lorsque nous mettons simplement à jour certaines propriétés de la collection d'éléments de collection, ne le signalez pas et l'interface utilisateur ne sera pas mise à jour.
Vous pouvez simplement implémenter INotifyPropertyChange dans votre classe Model. Et que lorsque nous mettons à jour certaines propriétés dans l'élément de collection, l'interface utilisateur sera automatiquement mise à jour.
et que
Dans mon cas, j'ai utilisé ListView to Bind pour cette collection et dans ItemTemplate, définissez Binding to Model et cela fonctionne bien.
Voici un extrait
Windows XAML:
Exemple de code de modèle:
Et l'implémentation de ViewModel:
la source
Solution simple pour la collecte d'observation standard que j'ai utilisée:
NE PAS AJOUTER à votre propriété OU CHANGER DIRECTEMENT ses éléments internes, mais plutôt créer une collection temporaire comme celle-ci
et ajouter des éléments ou apporter des modifications à tmpList,
puis transmettez-le à votre propriété réelle par cession.
cela modifiera toute la propriété, ce qui entraînera la notification de INotifyPropertyChanged selon vos besoins.
la source
J'essaie cette solution, mais ne fonctionne que pour moi comme un RaisePropertyChange ("SourceGroupeGridView") lorsque la collection a changé, qui a déclenché pour chaque élément ajouté ou modifié.
Le problème est dans:
NotifyCollectionChangedAction.Réinitialiser cette action pour effectuer une nouvelle liaison complète de tous les éléments dans groupedgrid, est équivalent à RaisePropertyChanged. Lorsque vous l'utilisez, tous les groupes de gridview sont actualisés.
Si vous souhaitez uniquement actualiser dans l'interface utilisateur le groupe du nouvel élément, vous n'utilisez pas l'action Réinitialiser, vous devrez simuler une action Ajouter dans la propriété de l'élément avec quelque chose comme ceci:
Désolé pour mon anglais, et merci pour le code de base :), j'espère que cela aidera quelqu'un ^ _ ^
Enjoi !!
la source
Voici une méthode d'extension pour la solution ci-dessus ...
la source
Au lieu d'un ObservableCollection ou TrulyObservableCollection, envisagez d'utiliser un BindingList et d'appeler la méthode ResetBindings.
Par exemple:
Étant donné un événement, tel qu'un clic, votre code ressemblerait à ceci:
Mon modèle ressemblait à ceci:
la source
BindingList
, mais il y a une limitation à cette approche que les autres réponses surmontent: cette technique repose sur la valeur en cours de modification dans le code et où un appel àResetBindings()
peut être ajouté. La plupart des autres réponses fonctionneront si les objets de la liste sont modifiés par d'autres moyens, tels que du code inaltérable ou d'une liaison à un second contrôle.Pour déclencher OnChange dans la liste ObservableCollection
Exemple:
la source
Voici ma version de l'implémentation. Il vérifie et renvoie une erreur, si les objets de la liste n'implémentent pas INotifyPropertyChanged, vous ne pouvez donc pas oublier ce problème lors du développement. À l'extérieur, vous utilisez l'événement ListItemChanged pour déterminer si la liste ou l'élément de liste lui-même a changé.
la source
Solution simple en 2 lignes de code. Utilisez simplement le constructeur de copie. Pas besoin d'écrire TrulyObservableCollection etc.
Exemple:
Une autre méthode sans constructeur de copie. Vous pouvez utiliser la sérialisation.
la source
Vous pouvez également utiliser cette méthode d'extension pour enregistrer facilement un gestionnaire pour le changement de propriété d'élément dans les collections pertinentes. Cette méthode est automatiquement ajoutée à toutes les collections implémentant INotifyCollectionChanged qui contiennent des éléments qui implémentent INotifyPropertyChanged:
Comment utiliser:
la source