2014-06-11 16 views
14

Wir sind auf einen seltsamen Fehler gestoßen, bei dem Probleme beim Debuggen auftreten.Warum sollte das Überschreiben von .GetHashCode diese datengebundenen Werte in WinForms löschen?

Wir haben einen MDI-Arbeitsbereich, der Microsoft CAB, DevExpress-Komponenten und .Net 3.5 verwendet.

Wenn Benutzer zwei Fenster im Arbeitsbereich öffnen, die jeweils ein an zwei separate Datenmodelle gebundenes UserControl enthalten, minimieren Sie beide, das erste zu minimierende Fenster erhält die gebundenen Felder, wenn das zweite minimiert wird. Die Methoden .Equals und .GetHashCode des Datenmodells wurden außer Kraft gesetzt, so dass beide Datenmodelle als gleich angesehen werden. Wenn wir das ändern, damit sie einzigartig sind, bekommen wir dieses Verhalten nicht.

Hier ist ein Beispiel Pseudo-Code, das Problem zeigt

var a = new MyWindow(); 
a.DataModel = new SomeClass(123); 
a.ShowInMdiWorkspace(); 

var b = new MyWindow(); 
b.DataModel = new SomeClass(123); 
b.ShowInMdiWorksace(); 

a.Minimize(); 

// If SomeClass.GetHashCode() is overwritten to consider two objects 
// as equal based on the value passed in, then the data bindings for A 
// get cleared on this call. If SomeClass.GetHashCode is unique, then 
// this problem does not happen. 
b.Minimize(); 

Hier ist der Call-Stack, wenn das zweite Fenster minimiert wird:

enter image description here

Am EndEditSession() Anruf in dem Stack-Trace oben, es ist Rufen EndEditSession für die Sekunde Fenster minimiert, während zu der Zeit der Stack Trace über die [External Code] t o der OnChange-Breakpoint, den ich gesetzt habe, wird die Änderungsmethode im ersten-Fenster ausgelöst.

EndEditSession() ist etwas Brauch wir implementiert haben, die so etwas wie dieses

protected void EndEditSession() 
{ 
    IBindingValue bv = null; 

    if (_bindingValues == null) 
     return; 

    if (_data != null) 
    { 
     foreach (KeyValuePair<string, IBindingValue> kvp in _bindingValues) 
     { 
      bv = kvp.Value; 
      if (bv.IsBindable) 
       ((PropertyManager)bv.Component.BindingContext[_data]).EndCurrentEdit(); 
     } 
    } 

} 

_bindingValues wird bevölkert aussieht, wenn die Usercontrol seine Datenbindungen initialisiert. Die Schlüsselfelder sind der Name des gebundenen Steuerelements und die Wertfelder sind ein benutzerdefiniertes Objekt, das das Steuerelement selbst, seinen Namen, seinen gebundenen Wert und seinen Standardwert speichert. bv.Component gibt die Steuerung, dass die Bindung an eingestellt wird, die im Fall von meinem Test ist eine maßgeschneiderte DevExpress LookupEdit

_data enthält das Datenmodell für die UserControl, und kann überprüfen, dass es zu der Instanz für den zweiten Satz wird Fenster.

Mein ursprünglicher Gedanke war, dass die BindingContext geteilt wurde, so dass die falsche PropertyManager zurückgegeben wurde, aber ich habe festgestellt, dass die .BindingContext für die beiden Formulare und Steuerelemente getrennt sind.

Ist es möglich, dass ein UserControl zwei getrennte Kopien mit zwei getrennten Instanzen eines Datenmodells gebunden würde seine Bindungen sich einlassen, wenn die GetHashCode Methode überschrieben worden ist, so dass die beiden Objekte als gleich betrachtet werden?

Ich bin nicht sehr vertraut mit den inneren Funktionen des WinForms-Bindungssystems oder mit genau, wie CAB MDI-Arbeitsbereich verwaltet wird.

Meine Theorie ist, dass, wenn das erste Fenster minimiert, es die Steuerelemente entlädt, Speicher zu sparen, dann, wenn das zweite Fenster minimiert die interne Hash-Tabelle, die die Bindungen verwaltet, wird falsch verwirrt und führt ein Update zum Abrufen von Daten aus das erste minimierte Fenster (das jetzt leer ist) und das Aktualisieren seiner Datenquelle.Es gibt viele Löcher in dieser Theorie, aber es ist das einzige, was ich mir vorstellen kann.

Antwort

0

BindingContext Objekt teilen ihre Felder und Eigenschaften nicht mit anderen BindingContext, weil ihre Felder und Eigenschaften nicht statisch sind.

Es ist jedoch möglich, ein BindingContext Objekt für mehrere Steuerelemente zu haben.

Im ersten Fall, wenn mehrere Kontrollen die gleichen Eltern haben und haben ihre eigenen nicht BindingContext dann BindingContext Eigenschaft dieser Kontrollen Control.Parent(.Parent...).BindingContext Objekt zurück.

var bindingContext = new BindingContext(); 
var a = new SomeControl(); 
var b = new SomeControl(); 
a.BindingContext = bindingContext; 
b.BindingContext = bindingContext; 

Im dritten Fall BindingContext kann so überschrieben:

Im zweiten Fall gibt es kann so etwas wie diese.

Ich weiß nicht, was in Ihrem Fall los ist, so kann ich nur empfehlen, so etwas wie dies vor der Initialisierung Datenbindungen zu tun:

var a = new SomeControl(); 
var b = new SomeControl(); 
a.BindingContext = new BindingContext(); 
b.BindingContext = new BindingContext(); 


Wenn dies Ihr Problem nicht lösen, dann brauchen Sie Überprüfen Sie das Bestücken Ihres _bindingValues Objekts. Es ist möglich, dass während des Auffüllens dieses Objekts mit falschen Werten gefüllt wird.

+0

Das war mein erster Gedanke auch, aber das gleiche Problem tritt immer noch auf, wenn Sie jedem Steuerelement zuweisen eigene 'BindingContext' – Rachel

+2

@Rachel Kannst du ein Beispielprojekt zur Verfügung stellen? Es scheint, dass es nicht genug Informationen über Sie Problem gibt. Ich denke, das Problem ist nicht mit BindingContext. Das Problem liegt möglicherweise in Ihrem _bindingValues-Objekt. – nempoBu4

+0

Ich konnte das in einem Beispielprojekt tatsächlich nicht reproduzieren, was ich denke, weil ich in meinem Beispiel keinen vollständigen MDI-Arbeitsbereich mit Smartparts erstellt habe. Der Beispielcode, mit dem ich arbeitete, ist nur ein Formular mit einem TabControl, einem benutzerdefinierten Objekt und einem benutzerdefinierten Benutzersteuerelement mit dem benutzerdefinierten Bindungscode. Ich werde es heute noch einmal versuchen und sehen, ob ich das Problem in einem größeren Beispielprojekt reproduzieren kann. – Rachel

1

Ich weiß nicht, die internen Abläufe den WinForm-Widget, aber es scheint, dass da ein Problem mit zwingenden begegnet ist gleich, dass Sie weg wären besser, arbeitet rund um.

Wenn Sie Gleichheit für eigene Zwecke bewerten müssen:

Ein Ansatz zu schaffen, ist Ihre eigene Methode Gleichheit zu bewerten, anstatt das Standardverhalten zu ändern.

Wenn Ihre Absicht ist es zu ändern, wie das Widget die Objekte behandelt:

Ein Ansatz ist es, ein statisches Objekt Fabrik für Ihre Klasse zu machen. Die Fabrik könnte eine Sammlung aller Objekte verwalten, die mit schwachen Referenzen erstellt wurden. Schwache Referenzen ermöglichen es dem GC, die Objekte zu sammeln. Die Fabrik kann dann die Sammlung von zuvor erstellten Objekten prüfen. Wenn eine Übereinstimmung gefunden wird, geben Sie die vorhandene zurück. Wenn nicht, dann erstelle es. Auf diese Art und Weise, anstatt zwei verschiedene Objekte zu haben, die zwei gleiche (Override gleich) auswerten, hätten Sie ein einzelnes Objekt mit zwei Referenzen, die gleich sind (gleicher Speicher).

Hoffentlich wird einer dieser anderen Ansätze Ihr Problem lösen.