Autor Beitrag
Csharp-programmierer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 14:19 
Hallo ihr Experten.
Ich bin gerade dabei, ein Programm über meine Einnahmen und Ausgaben zu schreiben, also sozusagen eine Finanzverwaltungssoftware für mich selbst. Auf der GUI befindet sich eine ListView. Ich habe selbst herausgefunden, wie ich die darin enthaltenen Daten speichern kann:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
try
            {
                string[] files = Directory.GetFiles(Path.Combine(Hauptpfad, "Finanzverwaltung"));
                foreach (string file in files)
                {
                    File.Delete(file);
                }

                foreach (ListViewItem i in this.listView1.Items)
                {
                    nummer++;
                    string s = Path.Combine(Hauptpfad, "Finanzverwaltung""Datei" + nummer.ToString());

                    if (i.SubItems[5].BackColor == Color.Red)
                        Farbe = "red";
                    else if (i.SubItems[5].BackColor == Color.Yellow)
                        Farbe = "yellow";
                    else if (i.SubItems[5].BackColor == Color.Lime)
                        Farbe = "lime";
                    else
                        Farbe = "default";

                    using (StreamWriter w = new StreamWriter(s))
                    {
                        w.WriteLine(i.Text);
                        w.WriteLine(i.SubItems[1].Text);
                        w.WriteLine(i.SubItems[2].Text);
                        w.WriteLine(i.SubItems[3].Text);
                        w.WriteLine(i.SubItems[4].Text);
                        w.WriteLine(Farbe);
                        w.Close();
                    }
                }

                nummer = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


Hier wird jedoch immer eine neue Datei erstellt, was mir für uneffizient erscheint. Kennt ihr eine bessere Methode?
Mfg :)


Moderiert von user profile iconTh69: Topic aus Algorithmen, Optimierung und Assembler verschoben am Di 05.01.2016 um 14:53
Moderiert von user profile iconTh69: Titel geändert (war "Algorithmus optimieren").

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 01.01.16 15:24 
Du möchtest Du vorhandene Datei erweitern, ohne soe zu löschen?
Lass das bleiben, ist einfacher :D

Du kannst natürlich auch zeilenweise durch gehen und bearbeiten (bei dir müsste das noch gehen), aber sobald die Daten etwas komplexer strukturiert sind (z.B. XML), ist das praktisch unmöglich.
Die einfachste und beste Variante ist, die vorhandenen Daten zu laden, im RAM zu bearbeiten und komplett in eine Datei zu schreiben.
Solange Du nur wenige Daten hast, geht das gut.

Sobald Du so viele Daten hast, dass das im RAM auf fällt, geht das natürlich nicht mehr, aber dann hast Du schon lange die Schwelle übertreten, ab der man sagen kann: Du brauchst eine Datenbank.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 18:04 
Verstehen Sie unter komplexen Daten sehr große Datenmengen aus String und Decimals oder die Datenstrukturen wie string, decimal, datetime usw?

Die Idee mit dem RAM ist nicht schlecht aber damit kenne ich mich nicht aus. Ich hätte vielleicht die Idee, dass man für jedes ListViewItem eine WriteLine im StreamWriter erzeugt. Also das man in der Datei in einer Zeile dann Datum, Betrag, usw hat. Und in der anderen Zeile das selbe nur mit anderen Werten. Mein Problem ist hinsichtlich dieser Sache, dass ich nicht weiß wie man diese Daten trennt und analysiert. Oder gibt es irgendeine Klasse in C# die das Speichern/Laden der Daten einer ListView übernimmt?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 01.01.16 18:44 
Ich rede von Objekten, die sich wieder aus Objekten und irgendwann aus den Grund-Typen zusammen setzen.
Das meine ich mit komplex. Z.B. bei Musik gibt es den Track, der in Alben bzw. Playlists organisiert ist, er hat auch eine Referenz zum Interpreten und je nachdem wie umfangreich das wird, geht noch viel mehr.

Große Datenmengen, da musst Du bei so einfach gehaltenen Daten vermutlich einige Millionen Datensätze anschleppen, damit es problematisch wird.

Und mit "Im RAM arbeiten" meine ich, die Daten einzulesen (die hast Du dann irgendwo in einer Variable), zu bearbeiten und wieder zu speichern.
Am besten wäre, wenn Du dir überlegst, wie deine Daten aussehen und dann eine Klasse dafür schreibst. Wenn Du Adressen speichern willst, würde ich z.B. eine Klasse mit Wohnort, PLZ, Straße und Hausnummer erstellen. Davon ein paar Objekte in einer Liste sind dann meine Daten, die ich direkt bearbeiten kann.
Die Tatsache, dass es irgendwo ein Objekt gibt, bedeutet, dass die Daten in diesem Objekt im RAM liegen. Somit kann ich sie im RAM bearbeiten. Nichts anderes tust Du die ganze Zeit, Du hast also sehr wohl Erfahrung damit ;)



So wie ich das sehe, ist für dich XML optimal.
.NET hat eingebaute Parser, die hervorragend und denkbar einfach funktionieren.
Der XMLSerializer zum Beispiel kann dir ein Objekt in XML serialisieren und umgekehrt. Der regelt auch das Lesen/Schreiben aus/in Dateien.
Einziges Hindernis ist, dass er nicht mit allen Klassen klar kommt. Das Dictionary zum Beispiel wird von Haus aus nicht unterstützt, das lässt sich aber leicht nach rüsten, gibt endlos Lösungen im Internet.
Dem XMLSerializer-Objekt gibst Du dann eine Liste mit deinen Daten und der schreibt die in eine Datei.
Beim Start des Programms schaust Du nach, ob es die Datei gibst, wenn ja liest Du auf die selbe Weise (Derserialisieren) deine Daten aus der Datei und arbeitest damit weiter. Existiert sie nicht, arbeitest Du mit einer leeren Liste, gibt ja keine Daten.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 19:04 
Hier ist jetzt der Klassencode:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
public class IO
    {
        public static IO Laden (string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);
            if(Directory.Exists(path))
            {
                using(FileStream stream = new FileStream(path, FileMode.Open))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(IO));
                    return (IO) xml.Deserialize(stream);
                }
            }
            else
            {
                return (new IO());
            }
        }

        public void Speichern(string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);

            using(FileStream fs = new FileStream(path, FileMode.Create))
            {
                XmlSerializer ser = new XmlSerializer(typeof(IO));
                ser.Serialize(fs, this);
            }
        }

        public string Datum { get; set; }
        public decimal AlterBetrag { get; set; }
        public string Art { get; set; }
        public decimal Betrag { get; set; }
        public string Beschreibung { get; set; }
        public decimal NeuerBetrag { get; set; }
        public List<IO> Objekte = new List<IO>();
    }


Das Problem jetzt jedoch ist, letztendlich habe ich ja den selben Salat wie vorher. Für jeden Eintrag in der ListView eine eigene XML- Datei. Das ist zwar jetzt nicht so im Code, aber das schlussfolgert sich ja daraus. Und ich weiß auch nicht, wie man die Liste Objekte mit Objekten füllt.
Kannst du mir bitte weiterhelfen?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 01.01.16 19:31 
Du möchtest eine List<IO> serialisieren nicht IO. Das gleiche Vorgehen das ich dir per PN in einem anderen Context bereits nahe gelegt habe. Eigentlich ist es haargenau die gleiche Problematik ob etwas ein Person ist oder ein Finanzdatensatz ist aus Softwaresicht völlig egal.

Ganz allgemein hängst du hier weil du dein Anwendung ausgehend von den Metaproblemen aus lösen willst. Das macht es nicht nur unnötig schwer sondern fast unmöglich am Ende bei was sinnvollem zu landen.
Du möchtest Datenanzeigen und Daten wegschreiben bringst die beiden Probleme in Beziehung und willst dann noch irgendwie deine Anwendunglogik ("Finanzverwaltung") dazwischen lügen.

Versuche zuerst allgemein das Finanzverwaltung-Problem darzustellen und schreibe dir dazu ein Klassenmodell aus Daten und Logikbestandteilen. Das muss nicht von Anfang funktionieren und kann hier und da aus Platzhaltern bestehen es ist aber letztlich der Kern deiner Anwendung. Woraus die genau besteht kann ich dir nicht sagen. Konten, Buchungen was auch immer Finanzverwaltung ist für mich erstmal nur ein Wort. Danach kannst du dich dann um die anderen Probleme kümmern. Zum Beispiel wie man das speichert oder wie man das in einer Oberfläche anzeigt. Spätestens dann wird dir auffallen das das die beiden Probleme völlig unabhängig voneinander sind und einzeln eher simpel lösbar sind. Nur wenn man die beiden Problem frühzeitig logisch miteinander vermischt sehen die nach einem Hindernis aus.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 20:11 
Gehr das so? Ich habe noch nie mit einer Liste von Objekten gearbeitet.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public static IO Laden (string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);
            if(Directory.Exists(path))
            {
                using(FileStream stream = new FileStream(path, FileMode.Open))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(IO));
                    return (IO) xml.Deserialize(stream);
                }
            }
            else
            {
                return (new IO());
            }
        }


Aber wie weise ich der Liste Werte zu?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 01.01.16 20:35 
Hast Du gelesen und verstanden, was Ralf geschrieben hat?
Das hat einen Sinn und es ist sehr wichtig, dass Du lernst, ein großes Problem in immer kleinere Teil-Probleme zu trennen, sonst übernimmst Du dich mit jedem noch so kleinen Projekt.


Hinzufügen von Elementen zu einer Liste geht mit der Add-Methode.
Das lässt sich auch mit ein wenig Hirnschmalz selber heraus finden. Google und die Intellisense-Hilfe von Visual Studio helfen da hervorragend.
Auch das ist sehr wichtig: Wir haben heute das Internet und viele Hilfsmittel, die gab's früher nicht. Nutze sie, das nimmt sehr viel Arbeit ab.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 21:32 
Naja das mit der Add-Methode wusste ich. Ist ja logisch aber eine Liste beinhaltet ja mehrere Objekte. Ich habe ja aber nur ein Objekt(IO). Aber wenn ihr mir sagt, ich müsste eine Liste anlegen, heißt das ja die Liste muss mehrere Objekte beinhalten. Aber wieso soll ich das Objekt IO mehrmals in die Liste einfügen? Was hat das für ein Sinn?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 01.01.16 21:36 
Den Sinn können wir nur erkennen, wenn wir dein Vorhaben kennen.

Grundsätzlich ist es aber in den meisten Fällen zemlich sinnlos, ein Objekt mehrmals in der selben Liste zu haben.
Das meine ich auch nicht, sondern dass Du die Objekte, die Du speichern willst - alle - in eine Liste legst.
Die speicherst Du dann auf einen Schlag und hast alle Objekte in einer Datei gespeichert.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 01.01.16 21:43 
In meiner ListView sind folgende Columns:
- Datum
- alter Netrag
- Art
- Einzahlung / Auszahlung
- neuer Betrag
- Beschreibung

Wie kann ich diese Daten in eine Liste adden?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 01.01.16 21:50 
- Erstell eine Klasse die diese Daten in entsprechenden Properties hält.
- Erstelle eine Liste von dieser Klasse. Eine Liste, wenn dir das noch unklar ist, ist einfach auch eine Klasse. Im Framework gibts dazu zum Beispiel List<T> als Listenklasse. Diese Listenklasse hat dann für alle denkbaren Bearbeitungen bezüglich einer Liste entsprechende Methoden (Add, Remove, Find etc.)
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 05.01.16 14:47 
Hallo. Ich habe es jetzt mit einem Konstruktor versucht:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
public class IO
    {
        private string datum, beschreibung ,art;
        private decimal alterBetrag, betrag, Neuerbetrag;
        public List<IO> Liste1 = new List<IO>();

        public IO (string datum, decimal alterbetrag, string art, decimal betrag, decimal neuerbetrag, string beschreibung)
        {
            this.datum = datum;
            this.beschreibung = beschreibung;
            this.alterBetrag = alterbetrag;
            this.betrag = betrag;
            this.Neuerbetrag = neuerbetrag;
        }

        public static IO Laden (string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);
            if(Directory.Exists(path))
            {
                using(FileStream stream = new FileStream(path, FileMode.Open))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(IO));
                    return (IO) xml.Deserialize(stream);
                }
            }
            else
            {
                return null;
            }
        }

        public void Speichern(string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);

            foreach (IO io in Liste1)
            {
                using (FileStream fs = new FileStream(path, FileMode.Create))
                {
                    XmlSerializer ser = new XmlSerializer(typeof(IO));
                    ser.Serialize(fs, io);
                }
            }
        }

        public string Datum { get; set; }
        public decimal AlterBetrag { get; set; }
        public string Art { get; set; }
        public decimal Betrag { get; set; }
        public string Beschreibung { get; set; }
        public decimal NeuerBetrag { get; set; }

        public static string defaultPath
        {
            get
            {
                return (Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung"));
            }
        }
    }


Speichern:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
private void toolStripButton1_Click(object sender, EventArgs e)
        {
            foreach(ListViewItem i in this.listView1.Items)
            {
                //string datum, decimal alterbetrag, string art, decimal betrag, decimal neuerbetrag, string beschreibung
                decimal alterbetrag;
                if(Decimal.TryParse(i.SubItems[1].Text, out alterbetrag))
                    xab = alterbetrag;

                decimal cbetrag;
                if(Decimal.TryParse(i.SubItems[3].Text, out cbetrag))
                    xbe = cbetrag;

                decimal cneuer;
                if(Decimal.TryParse(i.SubItems[5].Text, out cneuer))
                    xnb = cneuer;
                IO io = new IO(i.Text, alterbetrag, i.SubItems[2].Text, cbetrag, cneuer, i.SubItems[5].Text);
                io.Liste1.Add(new IO(i.Text, alterbetrag, i.SubItems[2].Text, cbetrag, cneuer, i.SubItems[5].Text));
                io.Speichern("Datei 1");
            }


Aber ich bekomme einen Fehler, dass dieses Objekt nicht serialisiert werden kann :(

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 05.01.16 15:51 
Hallo,

irgendwie scheinst du das mit der Liste falsch verstanden zu haben. M.E. macht es keinen Sinn, innerhalb der IO-Datenklasse (btw. eigenartiger Name für ein Datenobjekt!) die Liste zu verwalten.
Wenn du eine Liste serialisieren möchtest, dann benötigst du zwei Klassen:
1. eine Klasse, welche die Liste von Datenobjekten hält und die Serialisierungsmethoden (Laden, Speichern) bereitstellt
2. ein Datenklasse

Oder anders ausgedrückt: packe die Daten aus deiner IO-Klasse in eine eigene Klasse.

PS: Ich habe den Beitrag mal ins C#-Forum verschoben und den Titel angepaßt.
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Di 05.01.16 16:05 
Hallo,

also meines Wissens brauchst du zum serialisieren eine Klasse mit einem Standardkonstruktor, also dem Konstruktor, der keine Parameter hat. Das geht desshalb nur, weil der Serializer ein neues Objekt des Datentyps anlegen muss (in deinem Fall ist der Datentyp deine IO-Klasse). Wenn der Konstruktor aber Parameter hat, woher soll dann der Serializer wissen, was für Argumente er dem Konstruktor übergeben muss? Aber das nur mal so neben bei.


Deine ListView hat ja mehrere Einträge (die Items). Jeder Eintrag hat Details (SubItems). Zum Beispiel: deine ListView beinhaltet alle Schüler aus einer Klasse. Dann ist jedes Item ein Schüler und die Details sind dann wiederum Infos zu den Schülern (Namen, Alter, Wohnort, Noten, ...).

Was du jetzt getan hast, ist eine Klasse zu erstellen, die die ganze ListView beinhaltet (dein IO). In diesem IO willst du alle Daten aus der ListView übernehmen. In meinem Beispiel entspräche das einem Objekt, welches die ganze Klasse (hier meine ich die oben erwähnte Schulklasse, nicht die C# Klasse) beinhaltet. Das brauchst du aber nicht. Denn eine Schulklasse kann ja unterschiedlich viele Schüler haben (also kann deine ListView ja auch unterschiedlich viele Items haben).
Jetzt geht es erst mal darum, den richtigen Datentyp zu definieren (eine C# Klasse). Dabei gehst du vom obersten Layer los und arbeitest dich nach unten durch. Um auf mein Beispiel zurück zu kommen, sähe das ganze so aus:

1. Layer: Schulklasse
Deine Schulklasse ist einfach nur eine Ansammlung von beliebig vielen Schülern. Da die Schulklasse (außer ihren Schülern) keine zusätzlichen Infos besitzt, kannst du schon einen vorhandenen Datentyp benutzen - eine Liste. Also nimmst du für die Schulklasst eine List<Schüler>.
2. Layer: Der Schüler
Dein Schüler besitzt nun mehrere Infos. Jeder Schüler hat einen Namen, ein Alter und ein Wohnort. Also erstellst du dir eine Klasse mit dem Namen Schüler. In dieser Klasse legst du dann Variablen für Name, Alter und Wohnort an. Da der Name ein String ist und das Alter ein Integer sind diese Datentypen klar, also ist die Variable Name ein String und die Variable Alter ein Integer. Doch was ist Wohnort? Der Wohnort ist eine Adresse. Da es keinen Datentyp für sowas gibt, machst du wieder einen.
3. Layer: Die Adresse
Die Adresse besteht bekanntlich aus Ort, Postleitzahl, Straße und Hausnummer. Also erstellst du wieder eine C# Klasse und nennst sie Adresse. In dieser Klasse legst du die Variablen für Ort, Postleitzahl, Straße und Hausnummer an. Deren Datentypen sind wiederum alles Strings, also sind diese vier Variablen alle vom Typ String.

Jetzt hast du deine komplette Schulklasse in C# Code definiert. Nun musst du nur noch den 1. Layer speichern (man nennt das auch Wurzelelement oder Rootelement). Da der 1. Layer den 2. Layer beinhaltet und der 2. Layer wiederum den 3. Layer hat, werden alle Layer gespeichert.
Da der 1. Layer die Schulklasse ist und wir gesagt haben, dass die Schulklasse eine List<Schüler> ist, musst du auch genau das als Typ an den Serializer übergeben. Also wird letztendlich eine List<Schüler> gespeichert.

Ich hab mal schnell was gezeichnet um es verständlicher zu machen:
SerializerSerializer2

Dein Serializer ist dann einfach nur eine Hilfsklasse, die den XmlSerializer verwendet um die Daten zu speichern (wie Th69 gerade geschrieben hat).

Ich hoffe, ich konnte dir dein Problem und die Lösung nun besser verdeutlichen.
Einloggen, um Attachments anzusehen!
_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: Di 05.01.16 18:27 
Diese Spalten "AlterBetrag" und "NeuerBetrag" gehören nicht unbedingt in das Datenobjekt.
Der Wert dieser Spalten dient nur der Anzeige und wird aus der Liste auf Grundlage der vorherigen Buchungen ermittelt.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Di 05.01.16 20:47 
Ich glaube ich hab es jetzt verstanden:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
namespace Geldverwaltung
{
    public class IO
    {
        public List<IO> Liste1 = new List<IO>();

        public static IO Laden (string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);
            if(Directory.Exists(path))
            {
                using(FileStream stream = new FileStream(path, FileMode.Open))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(IO));
                    return (IO) xml.Deserialize(stream);
                }
            }
            else
            {
                return null;
            }
        }

        public void Speichern(string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);

            foreach (IO io in Liste1)
            {
                using (FileStream fs = new FileStream(path, FileMode.Create))
                {
                    XmlSerializer ser = new XmlSerializer(typeof(IO));
                    ser.Serialize(fs, io);
                }
            }
        }
        public static string defaultPath
        {
            get
            {
                return (Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung"));
            }
        }
    }
}


Datenklasse:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
namespace Geldverwaltung
{
    class Datenklasse
    {
        private string datum1, art1, beschreibing1;
        private decimal alterbetrag1, betrag1, neuerbetrag1;

        public Datenklasse(string datum, decimal alterbetrag, string art, decimal betrag, decimal neuerbetrag, string beschreibung)
        {
            this.datum1 = datum;
            this.art1 = art;
            this.beschreibing1 = beschreibung;
            this.alterbetrag1 = alterbetrag;
            this.betrag1 = betrag;
            this.neuerbetrag1 = neuerbetrag;
        }

        public string Datum { get; set; }
        public string Art { get; set; }
        public string Beschreibung { get; set; }
        public decimal AlterBetrag { get; set; }
        public decimal Betrag { get; set; }
        public decimal NeuerBetrag { get; set; }
    }
}


Aber wie verknüpfe ich diese Klassen jetzt?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 05.01.16 21:16 
Hallo,

du möchtest doch eine Liste der Daten haben, also
ausblenden C#-Quelltext
1:
public List<Datenklasse> Liste1 = new List<Datenklasse>();					

Und deine Serialisierung mußt du auch noch so anpassen, daß du List<Datenklasse> benutzt (und die foreach-Schleife ist dort auch überflüssig - du willst doch die Liste als Ganzes serialisieren und nicht jedes Element einzeln [und erst recht nicht alle in die selbe Datei (über-)schreiben]!).
Den Code solltest du jetzt selber dafür hinkriegen.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 05.01.16 21:24 
Die Datenklasse Klasse wird so nicht funktionieren. Der Konstruktor füllt private Felder an die du von außen nicht mehr rankommst. Die haben mit den Properties nix zu tun. Lass die Felder weg udn fülle direkt die Properties (aka Datum = datum; im Konstruktor u.s.w.)

Wenn IO dann die Klammer für die Datenklasse sein soll dann hilft dir die List<IO> nicht. Ein Liste von sich selbst ist meist merkwürdig IO hat eine List evon IO wo jedes Element wieder eine Liste von IO hat etc. . Du willst in IO eine Liste von Datenklasse und zwar auch eine Property und kein public Field. Die meisten Serializer serialisieren nur Properties.

Also eher
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
public class IO
{
    public List<Datenklasse> Datenklassen { get; set; }

    public IO()
    {
        Datenklassen = new List<Datenklasse>();
    }
}


In Laden()/Speichern() kannst du dann ganz simpel einfach IO serialisieren/deserialisieren lassen. Deine Liste ist ja einfach eine Property der Klasse und der Serialisierer der sich die Properties schnappt weiß was er bei einer Liste zu tun hat. Du musst da nix besonderes tun.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mi 06.01.16 13:03 
Ich habe es jetzt so gemacht, bekomme aber bei dem Bezeichner der Liste einen Fehler: Inkonsistenter Zugriff: Eigenschaftentyp ist weniger zugriffbar als Eigenschaft Geldverwaltung.IO.Datenklassen

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
namespace Geldverwaltung
{
    public class IO
    {
        public List<Datenklasse> Datenklassen { get; set; }
        public IO ()
        {
            Datenklassen = new List<Datenklasse>();
        }
        public static IO Laden (string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);
            if(Directory.Exists(path))
            {
                using(FileStream stream = new FileStream(path, FileMode.Open))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(IO));
                    return (IO) xml.Deserialize(stream);
                }
            }
            else
            {
                return null;
            }
        }

        public void Speichern(string FileName)
        {
            string s = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung");
            string path = Path.Combine(s, FileName);

            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                XmlSerializer ser = new XmlSerializer(typeof(IO));
                ser.Serialize(fs, Datenklassen);
            }
        }
        public static string defaultPath
        {
            get
            {
                return (Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Finanzverwaltung"));
            }
        }
    }
}


Datenklasse:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
namespace Geldverwaltung
{
    class Datenklasse
    {
        public Datenklasse(string datum, decimal alterbetrag, string art, decimal betrag, decimal neuerbetrag, string beschreibung)
        {
            Datum = datum;
            Art = art;
            Beschreibung = beschreibung;
            AlterBetrag = alterbetrag;
            Betrag = betrag;
            NeuerBetrag = neuerbetrag;
        }

        public string Datum { get; set; }
        public string Art { get; set; }
        public string Beschreibung { get; set; }
        public decimal AlterBetrag { get; set; }
        public decimal Betrag { get; set; }
        public decimal NeuerBetrag { get; set; }
    }
}


Speichernbutton:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
private void toolStripButton1_Click(object sender, EventArgs e)
        {
            foreach(ListViewItem i in this.listView1.Items)
            {
                //string datum, decimal alterbetrag, string art, decimal betrag, decimal neuerbetrag, string beschreibung
                decimal alterbetrag;
                if(Decimal.TryParse(i.SubItems[1].Text, out alterbetrag))
                    xab = alterbetrag;

                decimal cbetrag;
                if(Decimal.TryParse(i.SubItems[3].Text, out cbetrag))
                    xbe = cbetrag;

                decimal cneuer;
                if(Decimal.TryParse(i.SubItems[5].Text, out cneuer))
                    xnb = cneuer;
                Datenklasse daten = new Datenklasse(i.Text, alterbetrag, i.SubItems[2].Text, cbetrag, cneuer, i.SubItems[5].Text);
                IO funktionen = new IO();
                funktionen.Datenklassen.Add(daten);
                funktionen.Speichern("Datei 1");
            }
        }

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein