2010-03-17 1 views
2

J'ai une forme qui se lient à un objet, et lorsque l'utilisateur essaie de quitter la forme, je veux les mettre en garde si quoi que ce soit sur la forme a été modifiée, et les invite à enregistrer. Ma question est, y at-il un moyen d'y parvenir sans implémenter IComparar pour toutes mes classes dans l'objet lié? Je pensais s'il y avait un moyen de sérialiser mon objet lors du chargement du formulaire, et de faire une simple comparaison avec l'objet de changement qui est également sérialisé. Quelque chose comme une comparaison de chaînes.Vérifier le changement d'état dans les objets en utilisant la sérialisation?

Espoir qui ont du sens,

Merci

+0

Merci pour toutes les réponses, je suis au courant de la méthode IsDirty, mais je me demandais juste s'il y avait une autre façon de le faire. Maintenant, je me demande, si je sérialiser les objets en XML, serait-ce une méthode plus fiable. – sev7n

Répondre

0

Pour faire ce que vous essayez de faire, il y a probablement une méthode beaucoup plus simple: utiliser un drapeau « modifié » ou d'un événement.

Vous pouvez mettre en cascade ce jusqu'à plusieurs niveaux de contrôles utilisateur si besoin. Il suffit de déclarer l'événement comme celui-ci:

Alors, quel que soit le niveau, vous devez vérifier réellement des modifications, accrochez tous les événements.

public class MainForm : Form 
{ 
    private bool isDataModified; 

    public MainForm() 
    { 
     InitializeComponent(); 

     textBox1.TextChanged += DataModified; 
     textBox2.TextChanged += DataModified; 
     // etc. 
     userControl1.Modified += DataModified; 
     userControl2.Modified += DataModified; 
     // etc. 
    } 

    private void DataModified(object sender, EventArgs e) 
    { 
     isDataModified = true; 
    } 
} 

Ensuite, tout ce que vous avez à faire est de vérifier (et remise à zéro) le drapeau isDataModified en conséquence.

Il est vraiment pas beaucoup de travail, certainement plus facile que d'assurer que INotifyPropertyChanged est mis en œuvre pour chaque objet dans le graphique. Rappelez-vous, c'est une forme, vous ne se soucient pas vraiment que l'objet changé, vous vous souciez si l'utilisateur a fait un changement, et pour cela, vous voulez vérifier réellement les changements effectués par les contrôles.Oui, ce n'est pas parfait - vous êtes toujours confronté à la nuisance mineure de rapporter que les données ont été changées même lorsque l'utilisateur change quelque chose et le change ensuite. Mais je ne pense pas avoir jamais entendu une plainte à ce sujet, et l'utilisation de la sérialisation comme méthode de comparaison n'est tout simplement pas fiable. Ce que vous devez vraiment faire si vous voulez éliminer la confirmation de sauvegarde redondante est remplacer la méthode Equals de chaque objet dans le graphique et implémenter une opération réelle d'égalité des valeurs. Ou, si vous ne voulez pas conserver une copie de l'ancien graphique, utilisez une fonction de génération de somme de contrôle (les collisions sont possibles mais très improbables).

Mais je voudrais juste rester avec le drapeau. N'essayez pas de tricher pour échapper aux contrôles d'égalité. C'est en quelque sorte la même chose que d'essayer d'écrire une méthode automatique de clonage profond; vous pouvez essayer, mais tout ce que vous venez avec va être cassé parfois.

1

C'était asked before, sous la forme de comparaison 2 arbres objet à travers sérialisation. La réponse a été: il n'est pas fiable, il existe des contre-exemples d'objets égaux générant différents textes/données sérialisés.

+0

On dirait que le sérialiseur choisi est cassé, alors. Je serais intéressé à voir ça "avant". –

+0

@marc: voir modifier. –

+0

@Marc Gravell: Tant que les classes ont la possibilité de contrôler à la fois leurs opérations d'égalité et leurs représentations sérialisées, cela ne sera jamais totalement fiable, même si le sérialiseur fonctionne parfaitement. – Aaronaught

1

Si vous suivez le modèle régulier que les gens utilisent la mise en œuvre INotifyPropertyChanged, puis il suffit encore quelques lignes de code pour mettre en œuvre un IsDirty (ou IsChanged) drapeau sur l'objet de données.

tout d'abord créer une classe de base qui implémente les bases, et une vraie classe de données qui en découle:

public class BaseDataObject : INotifyPropertyChanged 
{ 

    public bool IsDirty 
    { 
     get { return _isDirty; } 
     protected set { _isDirty = value; } 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     _isDirty = true; 

     if (this.PropertyChanged != null) 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    private bool _isDirty; 
} 


public class MyRealDataObject : BaseDataObject 
{ 
    public int MyIntProperty 
    { 
     get { return _myIntProperty; } 
     set 
     { 
      bool changed = _myIntProperty != value; 
      if (changed) 
      { 
       _myIntProperty = value; 
       OnPropertyChanged("MyIntProperty"); 
      } 
     } 
    } 

    private int _myIntProperty; 
} 

Maintenant, chaque fois qu'un changement de propriété notifiables, IsDirty drapeau de l'objet de données seront mis à vrai. Pour vérifier les modifications, tout ce que vous avez à faire est d'énumérer votre collection d'objets et de vérifier l'indicateur IsDirty. Si vous êtes intelligent, vous pouvez le faire avec une déclaration LINQ:

bool changesMade = MyDataObjectCollection.Any(p => p.IsDirty == true).Count() > 0; 

... or .... 

bool changesMade = MyDataObjectCollection.Count(p => p.IsDirty == true) > 0; 

Si vos objets de données ne sont pas dans une belle collection, vous aurez juste à les itérer manuellement. Bien sûr, le modèle ci-dessus peut être refactorisé de différentes manières (hé, peut-être que vous n'utilisez même pas INotifyPropertyChanged parce que vous n'êtes pas une liaison de données aux éléments UI), mais cela vous donne un bon exemple de démarrage. tu veux.

Questions connexes