Hallo allerseits,
ich möchte ein ListView deserialisieren und auch wieder serialisieren. Bisher fällt mir nichts anderes ein, als die Items und Subitems in einer Laufschleife zu durchlaufen und die Deserialisierung nach Json durch eigenen Code durchzuführen. Es gibt die Methode ListViewItem.Deserialize(SerializationInfo, StreamingContext), aber damit komme ich irgendwie nicht klar.
Ein passendes Beispiel habe ich auch nicht gefunden.
Kann mir jemand helfen?
Man serialisiert keine UI Elemente, sondern Datenklassen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Aber es muss doch eine Datenklasse hinter ListView stecken - ich denke, dass es eine List ist. Aber wie hießt die und wie greife ich darauf zu?
Nein, das ist nicht die Idee hinter Serialisierung eigener Daten.
Ich dachte, dass Du Dir die Zeit genommen hättest die Links zu lesen, die ich/andere Dir in den anderen Themen gegeben haben. Deswegen antworten Dir die Leute mit den Links 😉
Punkt 1: man serialisiert keine Elemente einer UI.
Dass sowas in manchen UI-Elementen in WinForms enthalten war (noch ist), war damals ein pragmatischer Weg, den man aber bereut.
Das Zeug ist nur noch aus Kompatibilität drin - soll man nicht mehr verwenden (was auch in den Docs steht).
Punkt 2: verwendet man es doch, dann ist die Folge, dass Du eine Abhängigkeit an ein fremdes Element hast.
Das heisst: ändert sich was in/unter der ListView, dann funktioniert Deine gesamte Serialisierung nicht mehr.
Das ist eine Abhängigkeit, die man aus Konzeptgründen nicht haben will.
[Artikel] Drei-Schichten-Architektur
Die Grundidee hier ist, dass Dein gesamter Code auch funktionieren soll, wenn Du eine andere UI Technologie verwendest.
Daher haben modernere UI Frameworks auch keinerlei Serialisierungsunterstützung.
Daher ist die Lösung: eigene Klassen bauen für alles, was man selbst serialisiert / in der Verantwortung hat.
Und ja das heisst: mehr Code, beim Applikatiosstart Zeugs lesen, deserialisieren und damit die Liste füllen bzw. umgekehrt fürs Speichern.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich hatte es so gemacht, wie du gesagt hast, aber:
Mehrdimensionale Arrays können während Runtime nicht vergrößert werden.
string jsonString = File.ReadAllText(TextBoxPath.Text + TextBoxRGB.Text);
Farben = JsonSerializer.Deserialize<Farbe[]>(jsonString);
for (int loop = 0; loop < Farben.Length; loop++)
{
ListViewItem FarbeNr = ListViewRGB.Items.Add(Convert.ToString(Farben[loop].FarbeNr));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeRot));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeGruen));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeBlau));
FarbeNr.SubItems.Add(Farben[loop].FarbeBeschreibung);
}
Wenn der User eine neue Zeile im ListView erzeugt (also z.B. eine neue Farbe gelb einfügt), kann ich das nicht mehr in Farben kopieren, bzw. Farben nicht mehr erweitern. Also brauche ich etwas anderes. Letztendlich stellt sich die Frage, wie ich dieses User-Verhalten abbilden kann?
Arrays können generell nie erweitert werden, sondern müssen mit einer gewisse Größe erzeugt werden.
Ist das zu klein, muss ein neues Array erzeugt und die Inhalte übertragen werden.
Deswegen gibt es in .NET Listen, die einem sowas abnehmen.
List<T> Klasse (System.Collections.Generic)
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Und ich dachte, dass hinter dem UI-Element ListView eine solche Liste steckt, die man nur richtig ansprechen muss.
Also muss ich jetzt statt meines Arrays eine Liste erzeugen, und die Daten vom UI-Element dort speichern.
Ja, dahinter steckt eine Art von Collection (ob Liste oder Array spielt keine Rolle).
Aber man verwendet nicht die UI-Klassen der Liste für die Serialisierung - sondern eigene.
Also muss ich jetzt statt meines Arrays eine Liste erzeugen, und die Daten vom UI-Element dort speichern.
Ne, hab ich auch nicht geschrieben.
Hab geschrieben: eigene Klasse für die Daten.
Ob das in einem Array oder in einer Liste gespeichert wird, ist für die Serialisierung völlig egal.
Die Liste hab ich nur ins Spiel gebracht weil Du geschrieben hast
Mehrdimensionale Arrays können während Runtime nicht vergrößert werden.
Der Kernpunkt ist immer noch meine Aussage: eigene Klasse für jegliches Speichern von Inhalten.
Man serialisiert keine UI-Klassen/UI-Objekte.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ja, alles ok und akzeptiert. Aber ich bin damit leider nicht weiter.
Nochmal: ich habe ein ListView, in das ich (wie auch immer) 4 Farben eingetragen habe mit jeweils Nr, R-Wert, G-Wert, B-Wert, Beschreibung. Diese Daten habe (wie auch immer) als Json in eine Datei geschrieben. Nun fülle ich eine 5. Farbe in mein ListView und will alles nochmal als Json in der Datei haben.
Was muss ich tun? Wie muss mein Konzept für die Datenspeicherung aussehen?
Ein Tipp der hilft, den man auch in Schulungen macht: wenn Du den eigenen Code und Flow nicht verstehst, dann mal ihn wie ein Diagramm auf ein Papier.
Und wenn Du merkst, dass der Flow funktioniert, dann schreib ihn in Code.
Im Endeffekt, mit der Annahme, dass Farbe
Deine Datenklasse ist:
Lesen:
Farbe
für Farbe
in die ListView eintragenSchreiben:
Items.Count
weißt Du wie viele Elemente in der Liste sind und kannst mit dieser Info das Array initialisierenFarbe
übertragenFarbe
den Array Farben
hinzufügenFarben
schreibenEs ist schwer zu verstehen, wo genau Dein Problem ist.
Ich will Dir aber nicht den Code schreiben, Du sollst es ja verstehen, sodass es Ping macht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich versuche, jetzt Schritt für Schritt deinen Vorschlägen zu folgen.
Annahme, dass Farbe Deine Datenklasse ist
[Serializable]
public class Farbe
{
public byte FarbeNr { get; set; }
public byte FarbeRot { get; set; }
public byte FarbeGruen { get; set; }
public byte FarbeBlau { get; set; }
public string FarbeBeschreibung { get; set; }
public Farbe(byte farbeNr, byte farbeRot, byte farbeGruen, byte farbeBlau, string farbeBeschreibung)
{
FarbeNr = farbeNr;
FarbeRot = farbeRot;
FarbeGruen = farbeGruen;
FarbeBlau = farbeBlau;
FarbeBeschreibung = farbeBeschreibung;
}
}
- Farben lesen
- Farbe für Farbe in die ListView eintragen
Farbe[] Farben;
private void ButtonRGBLesen_Click(object sender, EventArgs e)
{
if (File.Exists(TextBoxPath.Text + TextBoxRGB.Text))
{
string jsonString = File.ReadAllText(TextBoxPath.Text + TextBoxRGB.Text);
Farben = JsonSerializer.Deserialize<Farbe[]>(jsonString);
for (int loop = 0; loop < Farben.Length; loop++)
{
ListViewItem FarbeNr = ListViewRGB.Items.Add(Convert.ToString(Farben[loop].FarbeNr));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeRot));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeGruen));
FarbeNr.SubItems.Add(Convert.ToString(Farben[loop].FarbeBlau));
FarbeNr.SubItems.Add(Farben[loop].FarbeBeschreibung);
}
}
else
{
MessageBox.Show(TextBoxPath.Text + TextBoxRGB.Text + " nicht gefunden");
}
}
- ListView Elemente nehmen, durch Items.Count weißt Du wie viele Elemente in der Liste sind und kannst mit dieser Info das Array initialisieren
Im Eventhandler mache ich dann folgendes:
Farbe[] Farben = new Farbe[ListViewRGB.Items.Count];
Ich meine, dass ich dadurch ein lokales Array mit einer festen Größe definiert habe.
Und dann habe ich ein Problem:
- Jeden Eintrag in Farbe übertragen
Wie kann ich einen Eintrag der in die Klasse Farbe übertragen? Wenn ich
Farben[loop].FarbeNr = Convert.ToByte(ListViewRGB.Items[loop].Text);
versuche, bekomme ich die Exception
System.NullReferenceException: "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."
Ich dachte, Farben sei die Instanz?
Ich meine, dass ich dadurch ein lokales Array mit einer festen Größe definiert habe.
Arrays haben immer eine feste Größe.
Ich dachte, Farben sei die Instanz?
Ja, Du hast das Array Farben
erzeugt. Das ist dann "leer".
Mit Farben[loop]
versuchst Du aber ein Objekt Farbe
zu verwenden, das nicht erzeugt wurde.
for index in listitems
Farbe farbe = new Farbe(mit Deinen Werten)
farben[index] = farbe
Das siehst Du auch im Debugger, mit denen sich solche Fehler sehr einfach finden lassen.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich merke, dass es bei mir mit der Objektorientierung noch ziemlich hapert.
Jetzt funktioniert es jedenfalls und für heute reicht es auch 😉
Objektorientierung ...da gehört mehr dazu als "nur" ein (oder mehrere) Instanzobjekt(e) anzulegen: Rheinwerk - Openbook OOP und Rheinwerk - Openbook VC# '12 (Kap. 3)
Goalkicker.com // DNC Magazine for .NET Developers // .NET Blogs zum Folgen
Software is like cathedrals: first we build them, then we pray 😉