Laden...

Combox bzw. DataGrid, Selection funktionert nicht mehr nach Ändern einer Property

Erstellt von ill_son vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.537 Views
I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren
Combox bzw. DataGrid, Selection funktionert nicht mehr nach Ändern einer Property

Hallo

mit folgendem Problem komme ich nicht weiter:

Ich habe ein UserControl über TemplateBinding an ein ViewModel gebunden. In diesem VM gibt es eine ObservableCollection<ClasseA> als ItemsSource für ein DataGrid im UserControl mit ClassA wie folgt und einem TextColumn für "Name".


public class ClassA
{
    private string _Name;
    public string Name
    {
        get{ return _Name; }
        set
        {
            if(_Name != value)
            {
                _Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    //... weitere, hier nicht relevante Properties 


    //Auschnitt von override Equals, GetHashCode und Operatoren
    public override bool Equals(object obj)
    {
        return Equals(obj as ClassA);
    }

    public bool Equals(ClassA other)
    {
        return other != null &&
               Name == other.Name;
    }
}

Mein Problem besteht darin, dass, wenn ich im DataGrid im TextColumn den Namen ändere, ich danach keine anderes Item mehr anwählen kann, bzw. dies dann nicht in die an SelectedItem gebundene Property weitergereicht wird. Ich hab schon rausgefunden, dass das irgendwie mit dem override Equals zusammen hängt, weiß aber nicht, wie ich das Problem beheben kann. Wenn ich das gesamte UserControl über das TemplateBinding neu aufrufe (anderes UC und dann wieder dieses), geht alles wieder und auch die Namensänderung ist übernommen.

Grüße, Alex

Final no hay nada más

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Ich habe die Ursache gefunden.

Wenn ich statt


public override int GetHashCode()
{
    return 539060726 + EqualityComparer<string>.Default.GetHashCode(Name);
}

dies hier


public override int GetHashCode()
{
    return base.GetHashCode();
}

verwende, taucht das Problem nicht auf. Wenn ich das richtig recherchiert habe, wird Equals nicht aufgerufen, wenn GetHashCode() schon unterschiedliche Werte liefert. Meine Frage wäre noch: Ist es legitim, das so zu implementieren, wenn es das macht, was es soll oder gibt es eine sauberere Lösung?

Grüße, Alex

Final no hay nada más

16.807 Beiträge seit 2008
vor 4 Jahren

Wie genau kommst Du denn auf den Inhalt Deiner GetHashCode Implementierung?

public override int GetHashCode()
{
    return base.GetHashCode();
}

Kannst Du auch gleich löschen.
Override und dann base aufrufen macht dann wenig Sinn, außer Code Noise.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Hallo Abt,

danke für deine Antwort.

Visual Studio Auto Generate liefert das:


public override int GetHashCode()
{
    return 539060726 + EqualityComparer<string>.Default.GetHashCode(Name);
}

base ist Quatsch, da hast du Recht.


+ EqualityComparer<string>.Default.GetHashCode(Name);

verursacht mein Problem. Bliebe noch


public override int GetHashCode()
{
    return 539060726;
}


???

Final no hay nada más

1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

Visual Studio Auto Generate? Kein Plan was das ist - aber: der Hashcode eines Objektes soll sich nicht ändern, was auch immer das generiert hat - ignoriert diese Regel - mit entsprechenden Folgen.

Auf der anderen Seite: Warum GetHashCode() überschreiben, wenns ohne perfekt funktioniert? Mir fällt hierzu in deinem Fall kein Grund ein. Also einfach das override löschen.
(Gründe das zu überschreiben sind ohnehin eher rar gesät...)

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Hallo Taipi,

"Generate overrides" findes du bei "Quick Actions and Refractorings". Visual Studio generiert das dann genauso, wie oben beschrieben. In der MSDN stand beim Pattern für override Equals, dass man auch GetHashCode überschreiben soll. Macht man das nicht, wirft Visual Studio auch eine entsprechende Warnung. Das mit dem Hash, der sich nicht ändern soll, habe ich auch gelesen, das passt ja dann nicht mehr. Etwas wiedersprüchlich das Ganze.

Final no hay nada más

1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

gut - dann meinst du die Standard-Refactorings - hab hier ReSharper im Einsatz - der hat mir solchen Unsinn noch nicht vorgeschlagen...^^

Zurück zum Thema:
Grundsätzlich sieht dein Code so aus, als ob weder Equals noch GetHashCode überschrieben werden müssten - denn beide machen im Original ihren Job wie sie sollen ohne dass du an Funktionalität verlierst.

Falls VS dir beides generiert hat: Würde ich so nicht mehr verwenden. Ein override macht man manuell wenn einem die Basisfunktionalität nicht passt oder die Methode als abstrakt markiert wurde. Nicht generell weil's geht...

LG

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Doch ich muss Equals überschreiben, da ich die Objekte in einem Projekt speichere (Serialisiere) und später wieder herstelle, dann funktioniert der Vergleich der Referenzen nicht mehr.

Final no hay nada más

16.807 Beiträge seit 2008
vor 4 Jahren

Du solltest aber weder UI-Objekte noch Business-Objekte irgendwo abspeichern....
[Artikel] Drei-Schichten-Architektur

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Ich speichere alle eingegebenen Daten, indem ich das oberste ViewModell serialisiere (Xml) und es dann bei Bedarf wieder lade. Wie kann ich das denn besser machen?

Final no hay nada más

16.807 Beiträge seit 2008
vor 4 Jahren

Zum Speichern verwendet man Entitäten; also Klassen, die genau einen gewissen Zustand.
Diese haben in 99,9999% der Fälle nichts mit der UI oder der Logik am Hut.

Ein ViewModel oder ein Business Model kannst Du oft auch gar nicht serialisieren, zB. aufgrund von Dependencies.
Zum Speichern verwendet man i.d.R. nur POCOs - und spricht dann von Entitäten.

Siehe eben auch [Artikel] Drei-Schichten-Architektur

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Ich gebe zu, dass ich mich da wohl noch mehr einlesen muss. Eine Frage hätte ich noch. Worin bestet jetzt das Problem? Im der Speicherung der Daten im Xml-Format als serialisiertes Objekt oder darin, wie man aus den eingegebenen Daten im ViewModel eine Datei erzeugt und später aus dieser Datei alles wieder rekonstruiert?

Final no hay nada más

16.807 Beiträge seit 2008
vor 4 Jahren

So wie ich das sehe prinzipiell an Deinem nicht MVVM-getreuen Aufbau.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Wieso das? Ich habe UI und ein daran gebundenes ViewModel, indem die eingegeben Daten stehen. Diese würde ich gern als Datei speichern. Was ist daran nicht MVVM?

Final no hay nada más

1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

mal von MVVM weg was mich an deinem Problem verwirrt:
Ja - beim Serialisieren und wieder Deserialisieren ändert sich der Verweis, den Equals verwendet - so weit - so gut. Aber warum in aller Welt ist das überhaupt von Belang?

Mischst du verschiedene Datenquellen, in denen sich dann Duplikate der deserialisierten Elemente befinden? Falls ja hätte dir der hier gezeigte Code kein Stückchen weitergeholfen 😕 (Es bringt ja nichts auf Basis eines Namens zu vergleichen, der sich offenbar auch jederzeit ändern kann - was du dann bräuchtest wäre eine unveränderliche Id)

Falls dem so ist - solltest du denke ich besser beschreiben was du eigentlich machst und vorhast - möglicherweise gibt es einen deutlich besseren Weg, der dir entsprechende Probleme spart.

Was deine Implementierung angeht: Du beschreibst lediglich einen Aufbau den mal wohl VVM nennen könnte - denn das zugrunde liegende Model fehlt ja. Allerdings würde dir das allein hier auch nicht weiterhelfen...

LG

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Ich habe zum Beispiel eine Liste von ClassA aus der wähle ich mir einen Eintrag aus und es ist wichtig, welcher das ist, da am Ende damit was berechnet wird. Und wenn ich das Projekt bzw. die Datei beim nächsten Mal öffne, soll natürlich dasselbe Objekt ausgewählt sein. Es soll denselben Zustand habe, wie beim Speichern. So kann man es kurz beschreiben.

Final no hay nada más

1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

nun - wenn man dort nach der Beschreibung geht - spielt es keine Rolle ob du Equals überschreibst oder nicht - sondern vielmehr welche Eigenschaften gespeichert wurden und dass eben das korrekte Element ausgewählt wird.

Welche Eigenschaften das Ding nun hat bestimmst du - und welches Objekt beim nächsten Start ausgewählt wird - könnte eine Guid sein, die du dir an anderer Stelle merkst. Alles kein Grund Equals und GetHashCode zu überschreiben.

LG

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 4 Jahren

Wenn ich dich richtig verstehe, müsste ich also anstatt mein VM zu Serialisieren aus dem ViewModel einen wie auch immer gearteten Datensatz generieren und den spiechern und beim Rücklesen aus diesen Daten dann das VM füttern?

Final no hay nada más

1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

nein - ViewModels generieren i.d.R. keine Models nur um diese zu speichern. Sie arbeiten lediglich damit.

Schau dir doch bitte mal wirklich die verlinkten Seiten zum Thema MVVM und 3-Schichten-Architektur an - dann stellt sich dir diese Frage gar nicht mehr...

LG