Comment permettre à un parent de la classe de connaître un changement de ses enfants?
Ceci est un exemple de code:
public class MyParent : INotifyPropertyChanged
{
List<MyChild> MyChildren;
public bool IsChanged
{
get
{
foreach (var child in MyChildren)
{
if (child.IsChanged) return true;
}
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
Disons que j'ai maintenant deux instances de mes classes, l'une comme myParent, et l'autre comme myChild.
J'ai deux éléments visuels, qui ont chacune une propriété liée à la IsChnaged propriété de mes instances; ElementA lié à myParent.IsChanged et ElementB lié à myChild.IsChanged.
Quand myChild.Valeur diffère de sa valeur par défaut, la myChild.IsChanged est définie sur true et le ElementB est mis à jour en conséquence.
Ce dont j'ai besoin, c'est quand l'une des myParent des enfants (ce qui n'est ici qu'un) ont leur IsChanged valeur est définie sur true, son propre (le parent) IsChanged valeur true et sa correspondante
élément (ElementA ici) être mis à jour en conséquence.
La myParent.IsChanged n'est lu qu'une seule fois (lorsque la liaison est définie) et il n'a pas de sens au sujet de ses enfants en train de changer. Où dois-je mettre de la RaiseChanged("IsChanged") pour MyParent? Comment puis-je informer le parent de savoir quand ses enfants ont changé?
Merci d'avance
C'est quelque chose que je tiens à éviter, je préfère ne pas introduire de la mère à l'enfant, soit dans le constructeur ou même comme une propriété. Est-il un autre chemin?
OriginalL'auteur iXed | 2011-07-11
Vous devez vous connecter pour publier un commentaire.
INotifyPropertyChanged
a déjà fourni le mécanisme pour vous: lePropertyChanged
événement. Juste le parent ajouter un gestionnaire pour ses enfantsPropertyChanged
, et ensuite dans celui de gestionnaire d'appelRaiseChanged("IsChanged");
Aussi, vous voudrez peut-être mettre la
INotifyPropertyChanged
mise en œuvre dans une classe de base, et vous avez votre (ce qui semble être) Viewmodel héritent de cette. Pas nécessaire pour cette option, bien sûr, mais elle permettra de rendre le code un peu plus propre.Mise à jour: Dans le parent de l'objet:
Vous n'avez pas à ajouter quoi que ce soit à l'enfant de la classe, puisqu'il est déjà levée de l'événement correct lorsqu'il change.
ok, je vais lui donner un essai
J'ai cette erreur: "Impossible de convertir implicitement le type de Système.EventHandler<Système.ComponentModel.PropertyChangedEventArgs>' pour 'Système.ComponentModel.PropertyChangedEventHandler'"
Désolé; n'ont pas la possibilité de compiler et tester. Vous pouvez simplement déclarer les gestionnaires comme
PropertyChangeEventHandler
dans ce cas.Merci pour votre réponse, cela a fonctionné assez bien, mais il y a un problème, je voudrais enregistrer mes objets à l'aide de la sérialisation, mais quand je les ouvre les ouvre les objets n'ont plus le PropertyChanged gestionnaire de défini pour eux. Toute solution à cela? BTW, je peut modifier votre réponse, donc il n'y aurait pas de confusion pour les autres?
OriginalL'auteur dlev
Faire ce genre de communication peut être difficile, surtout si vous voulez éviter les fuites de mémoire en raison de l'gestionnaires d'événements que vous vous accrochez. Il y a aussi le cas de la manipulation des éléments qui sont ajoutés /supprimés de la collection.
J'ai vraiment apprécié la puissance et la simplicité de la Continue LINQ projet sur codeplex. Il a quelques fonctionnalités très riche pour la création de "les Objets Réactifs", "Valeurs Continues", et "Continue Collections". Elles vous permettent de définir vos critères d'une expression Linq et de laisser le CLINQ bibliothèque de garder les valeurs sous-jacentes à jour en temps réel.
Dans votre cas, vous pourriez mettre en place le parent avec un ContinuousFirstOrDefault() requête linq qui a regardé pour tout enfant dont la "IsChanged == true". Dès qu'un enfant définit la valeur true et soulève PropertyChanged, la valeur continue permet de détecter le changement et à relever un correspondant PropertyChanged dans le parent.
Les avantages:
Voici ce que le code pourrait ressembler à:
Le code ci-dessus met en place le ContinuousFirstOrDefault dans le constructeur de sorte qu'il est toujours suivi. Cependant, dans certains cas, vous pouvez optimiser cette par paresseusement l'instanciation de la ContinuousFirstOrDefault uniquement lors de la lecture de "IsChanged" est appelé. De cette façon, vous ne commencez pas à surveiller les modifications jusqu'à ce que vous savez que quelque autre morceau de code se soucie.
Merci pour la réponse très!
OriginalL'auteur NathanAW
Vous pouvez simplifier les choses pour vous-même par le stockage de vos enfants dans un
ItemObservableCollection<T>
, tel que discuté dans cette réponse. Qui vous permettent de le faire:ItemObservableCollection. Voir l'autre fil, j'ai lié.
solution sympa, mais toujours pas aussi simple que cela
OriginalL'auteur Kent Boogaart
Quelque chose que je ne vois pas dans votre exemple de code à fournir est en réalité une référence de parent à enfant. Il ne suffit pas d'avoir une interface pour communiquer à travers, mais vous devez également créer la référence. Quelque chose comme
myChild.parent = this;
suivie par la liaison des gestionnaires d'événements à travers le canal, dans le "parent" de la propriété de l'objet enfant, il devrait ressembler à:Je n'ai pas assez de contexte pour parfaire ce code pour vous, mais cela devrait vous permettre de vous déplacer dans la bonne direction.
Comment pensez-vous vous attendez à eux de communiquer?
OriginalL'auteur Cos Callis
Je ne suis pas assez familier avec le code C++, mais cela sonne un peu comme le "modèle observateur" (Wikipedia, une autre bonne page pour la conception OO. En termes simples, toute instance devrait déclencher un événement à chaque fois qu'il a changé, et de toute autre instance qui contient une référence à elle peut attraper cet évènement et d'y réagir de façon appropriée.
OriginalL'auteur Christoph Jüngling