none
TreeView - Master/Detail - Ansatzpunkte -> XML Speicherung RRS feed

  • Frage

  • Hallo Zusammen!

    Ich suche Ansatzpunkte um folgendes zu realisieren.

    Evtl. gibt es irgendwo auch ein Beispiel.

    Gruppe1
        Untergruppe 1.1----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 1.2----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 1.3----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 1.4----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 1.5----------Wert1 String --------Wert2 Integer--------Wert3 Double
    Gruppe2
        Untergruppe 2.1----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 2.2----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 2.3----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 2.4----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 2.5----------Wert1 String --------Wert2 Integer--------Wert3 Double 
    Gruppe3
        Untergruppe 3.1----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 3.2----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 3.3----------Wert1 String --------Wert2 Integer--------Wert3 Double    Untergruppe 3.4----------Wert1 String --------Wert2 Integer--------Wert3 Double
        Untergruppe 3.5----------Wert1 String --------Wert2 Integer--------Wert3 Double 

          

    Ziel:

    Ich lade eine XML Datei, danach füllt sich ein TreeView.

    Die Werte, Untergruppe ----------Wert1 String --------Wert2 Integer--------Wert3 Double
    lassen sich vom Bediener aus editieren, löschen, hinzufügen.

            Danach Speicherung der Daten, die später wieder eingelesen werden können.

    Fragen:

    • Wie könnte man das gut umsetzen? Welche Klassen, Tools?
    • Idee, Dataset?
    • XML, gibt es ja auch mehrere Möglichkeiten, welche wäre da am einfachsten?

    Problem:

    •   Geht das überhaupt, dass man in einem TreeView editieren kann etc.?
        Müßte wahrscheinlich ein TreeView, ListView sein, dann ist das Problem mit Master/Detail

    Danke schon jetzt für gute Tipps, Beispiele.

    Viele liebe Grüße Sandra

    Montag, 26. Januar 2015 09:11

Antworten

  • Hi Sandra,
    nachfolgend mal ein Beispiel mit typisiertem DataSet, LinQ, Änderung und Rückschreiben. Das typisierte DataSet habe ich mit dem Designer erzeugt und in der XML-Datei ist auch das Schema enthalten.

    using System;
    using System.Data;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
      public partial class Form8 : Form
      {
        public Form8()
        {
          InitializeComponent();
        }
    
        DataGridView dgv1 = new DataGridView() { Dock = DockStyle.Fill };
        DataGridView dgv2 = new DataGridView() { Dock = DockStyle.Fill };
        SplitContainer spc = new SplitContainer() { Dock = DockStyle.Fill };
    
        Form8DataSet ds = new Form8DataSet();
    
        DataTable dtGruppe = new DataTable() { TableName = "Gruppe" };
        DataTable dtUntergruppe = new DataTable() { TableName = "Untergruppe" };
    
        BindingSource bs1;
        BindingSource bs2;
    
        protected override void OnLoad(EventArgs e)
        {
          base.OnLoad(e);
          // Steuerelemente anzeigen
          this.Controls.AddRange(new Control[] { spc });
          this.spc.Panel1.Controls.Add(dgv1);
          this.spc.Panel2.Controls.Add(dgv2);
          // Daten laden
          DataSet ds2 = new DataSet();
          ds2.ReadXml("c:\\temp\\form8.xml");
          ds.Merge(ds2);
    
          //  Bindingsource aufbauen
          this.bs1 = new BindingSource(ds, "Gruppe");
          //this.bs2 = new BindingSource(ds, "Untergruppe");
          this.bs2 = new BindingSource(bs1, "Rel1");
          // Daten binden
          this.dgv1.DataSource = bs1;
          this.dgv2.DataSource = bs2;
          // Datensatz finden, ändern und rückschreiben
          var res = (from itm in ds.Untergruppe 
                     where itm.Untergruppe == "Untergruppe 14.4" 
                     select itm).FirstOrDefault();
          if (res != null) res.Wert3 = DateTime.Now.Millisecond;
          ds.WriteXml("c:\\temp\\form8.xml", XmlWriteMode.WriteSchema);
        }
      }
    }
    
    --
    Peter
    • Als Antwort markiert Sandra Maier Sonntag, 1. Februar 2015 11:31
    Samstag, 31. Januar 2015 17:16
  • Hi Sandra,
    meine XML-Datei ist mit Schema und da gibt es Konflikte beim Laden in das typisierte Dataset. Das kann man mit Merge umgehen.

    --
    Peter

    • Als Antwort markiert Sandra Maier Mittwoch, 4. Februar 2015 14:56
    Sonntag, 1. Februar 2015 18:03

Alle Antworten

  • Hallo Sandra Maier,

    ein TreeView dient der Darstellung von hierarchischen Strukturen und enthält typischerweise keine Werte. Ich denke mit dem TreeView bist du beim falschen Control für deine Zwecke. Typischerweise wird ein TreeView jedenfalls nicht zum editieren verwendet. Man kann das natürlich alles möglich machen, halte ich aber für keine gute Idee.

    Was Du suchst klingt für mich eher nach einem Grid, wie es zum Beispiel hier angeboten wird:http://www.bcgsoft.com/featuretour/tour196.htm

    Vielleicht sind ja auch noch ganz andere Darstellung denkbar oder sinnvoller.

    Eine Abbildung in einer XML-Strukur erscheint mir simpel, daher weiß ich nicht was ich dahingehend noch sagen könnte.

    Die interne Datenstruktur hängt natürlich davon ab was du mit den Daten machen möchtest - oder soll das einfach wieder in die XML geschrieben werden?

    Grüße


    - Florian

    Montag, 26. Januar 2015 13:08
  • Was Du suchst klingt für mich eher nach einem Grid, wie es zum Beispiel hier angeboten wird:http://www.bcgsoft.com/featuretour/tour196.htm

    Vielleicht sind ja auch noch ganz andere Darstellung denkbar oder sinnvoller.

    Eine Abbildung in einer XML-Strukur erscheint mir simpel, daher weiß ich nicht was ich dahingehend noch sagen könnte.

    Die interne Datenstruktur hängt natürlich davon ab was du mit den Daten machen möchtest - oder soll das einfach wieder in die XML geschrieben werden?

    Hallo Florian,

    ja prinzipiell hast Du Recht.

    Hast Du ein Freeware Beispiel für so ein Grid? Master-Detail, Verknüpfung Primär-/Fremdschlüssel ist mein Problem.

    Mein Problem.

    Wie bilde ich die obige Struktur als XML ab?

    Wie schreibe ich die Werte rein? Wie lese ich die Werte raus? Was ist bei den Datentypen zu beachten?

    String, int, double?

    Viele liebe Grüße Sandra.

    Dienstag, 27. Januar 2015 08:09
  • Hallo Sandra,

    eine Freeware Version kenne ich dazu nicht, kann natürlich was geben.

    Für die Abbildung der XML Strukur hatte ich diese beim letzten mal schlicht angelegt und dann die XSD zum XML erzeugt (https://msdn.microsoft.com/de-de/library/x6c1kb0s(v=vs.90).aspx), ggfls. muss man da noch etwas nacharbeiten.

    Die XML könnte so aussehen, das nur als Beispiel:

    <?xml version="1.0" standalone="yes"?>
    <Gruppen>
    	<Gruppe name="Gruppe1">
    		<Untergruppe name="Untergruppe 1.1">
    			<String>mein Text</String>
    			<Integer>123</Integer>
    			<Double>12.4</Double>
    		</Untergruppe>
    	</Gruppe>
    </Gruppen>

    Mit der XSD liegt dir dann auch die Datenstruktur vor, mit der du in deinem C# Programm auf der XML arbeiten kannst. Das Dataset steht dann zur Verfügung und es könnte wie im folgenden Code-Beispiel die XML-Datei (im Beispiel in der Variable XML-File) eingelesen werden.

    Gruppen GruppenData = new Gruppen();
    GruppenData.ReadXml(XML-File);
    

    Analog zu ReadXml, beim schreiben WriteXml verwenden. Nach dem einlesen kann man die Werte auslesen oder neu beschreiben.

    Bei double Werten musst du auf die Lokalisierung achten!

    Ich hab bestimmt ein paar Details ausgelassen, ist schon etwas her dass ich das gemacht habe - mache das eher in C++. 

    Grüße


    - Florian

    Dienstag, 27. Januar 2015 08:54
  • eine Freeware Version kenne ich dazu nicht, kann natürlich was geben.

    Hallo Florian,

    Danke. Falls Du (oder andere im Forum) dennoch ein prägnantes Beispiel hast, findest wäre es toll.

    Man könnte es ja so machen.

      DataGrid - Gruppe - Master

           DataGrid - Elemente - Detail

    Wenn man die Verknüpfungen korrekt angibt, macht ist es bestimmt einfach.

        Vielleicht gibt es dazu auch irgendwo eine Anleitung.

    Ich klicke ja jetzt in den Master Part, dann müssen unten die zugehörigen Details angezeigt werden.

        Hinzufügen, editieren, löschen.

    Grüße Sandra

    Dienstag, 27. Januar 2015 09:08
  • Hi Sandra,
    mit WPF als Alternative gäbe es viele Möglichkeiten zur Lösung dieser Frage.

    Wenn es WindowsForms sein sollen, dann wäre eine Lösung mit 2 DataGrids, DataSet mit DataRelations und BindingSources ein einfacher Lösungsweg. Das DataSet kann man als XML-Datei speichern und von dort wieder laden.

    --
    Peter

    Dienstag, 27. Januar 2015 09:47
  • Hallo Sandra,

    wie bereits vorher schon richtig erwähnt, sollte man für so eine Aufgabenstellung eher einen Grid benutzen
    Nachdem du aber trotzdem einen TreeView haben möchtest, kannst du auch die beiden Varianten kombinieren.

    Ein sehr gutes Beispiel hierfür findest du hier: http://www.codeproject.com/Articles/3225/TreeListView
    Und hier: http://www.codeproject.com/Articles/23746/TreeView-with-Columns

    Um auf deine anderen Fragen einzugehen:

    Hier findest du ein gutes Beispiel wie du mit C# XML-Trees abbilden bzw. generieren kannst:
    https://msdn.microsoft.com/en-us/library/bb387089.aspx

    Du kannst natürlich die Werte auch ich einer Datenbank speichern, in C# einlesen, diese im Programm abbilden und anschließend als XML exportieren.

    Was die Variablen betrifft: Hier findest du eine gute Übersicht der wichtigsten C# Variablen und deren Eigenschaften: http://www.tutorialspoint.com/csharp/csharp_data_types.htm

    lg
    mp

    Dienstag, 27. Januar 2015 11:12
  • Wenn es WindowsForms sein sollen, dann wäre eine Lösung mit 2 DataGrids, DataSet mit DataRelations und BindingSources ein einfacher Lösungsweg. Das DataSet kann man als XML-Datei speichern und von dort wieder laden.

    Hallo Peter,

    hast Du hierzu ein Beispiel parat. Ja WindowsForms. Danke im Voraus.

    Viele Grüße Sandra

    Dienstag, 27. Januar 2015 11:33
  • wie bereits vorher schon richtig erwähnt, sollte man für so eine Aufgabenstellung eher einen Grid benutzen
    Nachdem du aber trotzdem einen TreeView haben möchtest, kannst du auch die beiden Varianten kombinieren.

    Hallo MP,

    Danke für Deine Antwort. Zunächst suche ich eine nachvollziehbare Lösung, nicht zu komplex und versuche es über das Grid zu lösen, Standardtools in VS2010.

    Evtl. hat Peter eine anschauliches Beispiel oder Du kennst eins.

    Kein Ownerdraw etc., für mich muss es nachvollziehbar sein.

    DANKE.

    Viele Grüße Sandra

    Dienstag, 27. Januar 2015 11:39
  • Hallo!

    Wenn du nur nach einem einfachen Beispiel suchst, sieh dir den Code mal an:

    using System;
    using System.Data;
    using System.Windows.Forms;
    using System.Xml;
    using System.Data;
    
    namespace WindowsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                try
                {
                    XmlReader xmlFile ;
                    xmlFile = XmlReader.Create("Product.xml", new XmlReaderSettings());
                    DataSet ds = new DataSet();
                    ds.ReadXml(xmlFile);
                    dataGridView1.DataSource = ds.Tables[0];
                }
                catch (Exception ex)
                {
                    MessageBox.Show (ex.ToString());
                } 
            }
    
    
        }
    }
    

    Quelle: http://csharp.net-informations.com/xml/xml-to-datagridview.htm

    Weitere Beispiele findest du hier:

    http://www.c-sharpcorner.com/UploadFile/mahesh/load-xml-file-into-a-datagridview-using-C-Sharp/

    http://stackoverflow.com/questions/18114518/how-to-load-a-datagridview-with-my-data-from-xml

    sg
    mp

    Dienstag, 27. Januar 2015 11:51
  • Hi Sandra,
    nachfolgend ein kleines Beispiel:

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
      public partial class Form7 : Form
      {
        public Form7()
        {
          InitializeComponent();
        }
    
        DataGridView dgv1 = new DataGridView() { Dock = DockStyle.Fill };
        DataGridView dgv2 = new DataGridView() { Dock = DockStyle.Fill };
        SplitContainer spc = new SplitContainer() { Dock = DockStyle.Fill };
    
        DataSet ds = new DataSet();
        DataTable dtGruppe = new DataTable() { TableName = "Gruppe" };
        DataTable dtUntergruppe = new DataTable() { TableName = "Untergruppe" };
    
        BindingSource bs1;
        BindingSource bs2;
    
        protected override void OnLoad(EventArgs e)
        {
          base.OnLoad(e);
          // Steuerelemente anzeigen
          this.Controls.AddRange(new Control[] { spc });
          this.spc.Panel1.Controls.Add(dgv1);
          this.spc.Panel2.Controls.Add(dgv2);
          // Demodaten erzeugen
          this.dtGruppe.Columns.Add("ID", typeof(int));
          this.dtGruppe.Columns.Add("Gruppe", typeof(string));
          this.dtUntergruppe.Columns.Add("ID", typeof(int));
          this.dtUntergruppe.Columns.Add("FK", typeof(int));
          this.dtUntergruppe.Columns.Add("Untergruppe", typeof(string));
          this.dtUntergruppe.Columns.Add("Wert1", typeof(string));
          this.dtUntergruppe.Columns.Add("Wert2", typeof(int));
          this.dtUntergruppe.Columns.Add("Wert3", typeof(double));
          for (int i = 1; i < 21; i++)
          {
            DataRow dr = dtGruppe.NewRow();
            dr[0] = i;
            dr[1] = string.Format("Gruppe{0}", i);
            this.dtGruppe.Rows.Add(dr);
          }
          for (int i = 1; i < 100; i++)
          {
            DataRow dr = dtUntergruppe.NewRow();
            int k = (i + 4) / 5;
            dr[0] = i;
            dr[1] = k;
            dr[2] = string.Format("Untergruppe {0}.{1}", k, i - k * 5 + 5);
            dr[3] = string.Format("Wert1 {0}", i);
            dr[4] = i;
            dr[5] = i * 1.1;
            this.dtUntergruppe.Rows.Add(dr);
          }
          // DataSet aufbauen
          this.ds.Tables.AddRange(new DataTable[] { dtGruppe, dtUntergruppe });
          // Beziehung
          this.ds.Relations.Add("Rel1", dtGruppe.Columns[0], dtUntergruppe.Columns[1]);
          // Bindingsource aufbauen
          this.bs1 = new BindingSource(ds, "Gruppe");
          //this.bs2 = new BindingSource(ds, "Untergruppe");
          this.bs2 = new BindingSource(bs1, "Rel1");
          // Daten binden
          this.dgv1.DataSource = bs1;
          this.dgv2.DataSource = bs2;
        }
      }
    }

    --
    Peter

    Dienstag, 27. Januar 2015 12:28
  • Hallo Peter,

    schön das passt und anschaulich.

    Das ist dann der Knackpunkt.

     // DataSet aufbauen
        this.ds.Tables.AddRange(new DataTable[] { dtGruppe, dtUntergruppe });
     // Beziehung
        this.ds.Relations.Add("Rel1", dtGruppe.Columns[0], dtUntergruppe.Columns[1]);
     // Bindingsource aufbauen

    Das Speichern, wie würdest Du das machen? Dataset und auch SaveXML ?

    Es gibt eben viele XML Klassen.

    Zur Laufzeit, evtl. über LinQ Werte filtern, ändern speichern.

    Untergruppe 14.4 alle Werte auslesen, ändern und speichern.Toll

    Prinzipiell wirklich gut und kurz.

    // Beziehung
         
    this.ds.Relations.Add("Rel1", dtGruppe.Columns[0], dtUntergruppe.Columns[1]);

    Sollte ich das über den Editor machen, weißt du wo man da die Relation angibt?

    Ich könnte ja auch über den Editor die 2 Tabellen aufbauen.

    Wäre noch nett. Das hilft schon mal. Nicht so schwer, man muss es halt wissen.

    Viele liebe Grüße Sandra



    • Bearbeitet Sandra Maier Dienstag, 27. Januar 2015 20:42 Format
    Dienstag, 27. Januar 2015 20:40
  • Hi Sandra,
    Du kannst vieles aus meinem Codebeispiel auch mit "Klicki-Bunti" machen. Ich versuche, vieles selbst zu machen und in Klassen zu kapseln und über Parameter zu verwalten, z.B. die Bezeichnung der Beziehung. Das erleichtert mir, den Überlick zu behalten. Auch für Demozwecke ist es einfacher, auf den Designer zu verzichten.

    Auf die Frage, wie die Daten gespeichert werden sollten, kann ich keine Antwort geben. Dazu kenne ich das Projekt und das zu erreichende Ziel nicht. Vor dem Programmieren sollte erst einmal das Prozess-Design stehen: Daten erfassen - verarbeiten - anzeigen/auswerten incl. aller zu beachtenden Nebenbedingungen (z.B. Parallelverarbeitung von mehreren Plätzen aus). Wenn das spezifiziert ist, kann man das Datenschema für den Prozess festlegen. Danach kann man festlegen, wie und wo gespeichert werden soll (XML oder Datenbankserver, welcher Datenbankserver oder Service im Netz). Erst dann sollte man die Bedientechnologien festlegen, die u.a. auch die Oberflächen für Erfassung, Bearbeitung und Auswertungen beinhaltet.

    Wenn Du Dich für ein DataSet als internen Datenpuffer für den Prozess entschieden hast, es nur eine Einplatzlösung wird (keine parallele Bearbeitung der gespeicherten Daten) und die zu speichernden Daten nur aus dem Prozess entstehen, dann kann das Speichern des DataSets als XML-Datei ein optimale Lösung sein. Wenn jedoch zukünftig auch eine WPF-Oberfläche für den Prozess geplant ist, sollte man besser auf Listen umsteigen, die dann auch als XML gespeichert und geladen werden können. Wenn die Datenmengen umfangreich werden können, sollte besser ein Datenbankserver in Betracht gezogen werden. Wenn die Daten an verschiedenen Arbeitsplätzen zu bearbeiten sind, musst du ein zentrale Datenablage planen, was bei überschaubaren Datenmenge auch ein Service im Netz sein kann, der serialisierte Listen bereitstellt.

    Übrigens hat LinQ mit der Ablage nichts zu tun. Es kann nur auswählen, nicht speichern. Zum Speichern musst Du andere Mittel nutzen, bei DataSets ADO.NET oder ggf. EDM.

    Eine XML-Datei ist eine sequentielle Datei, in der man nicht so einfach mal Abschnitte (Deine Untergruppe 14.1) verändern kann. Bei einer Datenbank ist das problemlos möglich.

    --
    Peter

    Mittwoch, 28. Januar 2015 05:31
  • Wenn Du Dich für ein DataSet als internen Datenpuffer für den Prozess entschieden hast, es nur eine Einplatzlösung wird (keine parallele Bearbeitung der gespeicherten Daten) und die zu speichernden Daten nur aus dem Prozess entstehen, dann kann das Speichern des DataSets als XML-Datei ein optimale Lösung sein.

    Hallo Peter,

    nur Einplatzlösung also XML Datei.

    Dabei sollte eben die üblichen Such-,Filter-,Editiere-, Löschen-, Speichern, Hinzufügen gehen.

    Evtl. hast da noch ein kleines Beispiel.

    z.B. Untergruppe 14.4 alle Werte auslesen, ändern und speichern

          Wird man über LinQ machen, oder?

    Grüße Sandra

    Mittwoch, 28. Januar 2015 05:47
  • Hi Sandra,
    für Suche und Filtern musst Du eine Strategie formulieren. In meinem Beispiel nutze ich BindingSources, die Sortieren und Filtern enthalten. Suche lohnt sich nur in großen Datenmengen, was ggf. XML widerspricht.

    Editieren, Löschen Hinzufügen kann man über das Grid realisieren, wenn nichts anderes in der Bedientechnologie vorgegeben wurde.

    Laden und Speichern kann man die XML-Datei mit dem Methoden des DataSets, wobei immer alles geladen und gespeichert wird.

    --
    Peter

    Mittwoch, 28. Januar 2015 06:57

  • für Suche und Filtern musst Du eine Strategie formulieren. In meinem Beispiel nutze ich BindingSources, die Sortieren und Filtern enthalten. Suche lohnt sich nur in großen Datenmengen, was ggf. XML widerspricht.

    Hallo Peter,

    A) Der Bediener lädt das XML, die Struktur, ändert, speichert etc.

    B) Im Hintergrund, das Programm, lädt genau diese XML Datei, liest einen Wert heraus, ändert diesen und es wird gespeichert. Öffnet der Bediener die Datei, sieht er den abgeänderten Wert.

        Kurzum, ich muss das XML File parsen. Was bietet sich da an.

    Konkret

      Untergruppe 14.4 alle Werte auslesen, ändern und speichern.

    Im Hintergrund suche ich die Untergruppe 14.4, lese die Werte aus.

         Ändere diese ab, speichere die Datei, also ohne UserInterface.

    Hoffe ich habe es rübergebracht und Danke im Voraus.

    Viele Grüße Sandra

    Mittwoch, 28. Januar 2015 22:18
  • Hi Sandra,
    richtig verstanden habe ich Deinen Beitrag nicht.

    Zu A) Bisher war ich der Meinung, dass Du eine zweistufige Struktur hast (Gruppe - Untergruppe). Eine Änderung der Struktur (mehr Hierarchiestufen) bedeutet auch Programmänderungen, wenn Du zur Anzeige Datagrids benutzt. Bei variabler Struktur solltest Du gleich auf entsprechende Steuerelemente zurückgreifen. Da bietet sich das TreeView-Steuerelement an. Damit kannst Du auf beliebige Strukturen reagieren, vorausgesetzt, die Knoten werden Durch Dein Programm unterstützt.

    Zu B) Die XML-Datei ist eine sequentielle Datei. Etwas in der Mitte der Datei zu ändern, erfordert ein vollständiges Lesen in einen Puffer, Änderungen im Puffer und vollständiges Rückspeichern. In diesen Vorgang kann man auch einen Parser integrieren, um nicht alle Daten vollständig im Speicher halten zu müssen. Es bleibt aber dabei, dass der Vorgang einem vollständigen Kopiervorgang entspricht.

    Je nach Datenmenge und zur Verfügung stehendem Speicherplatz im Rechner muss entschieden werden, ob die gesamte Datei eingelesen und zwischengepuffert wird.

    Wenn die gesamte Datei eingelesen werden soll, dann bieten sich als Datenpuffer ein DataSet, ein XElement oder auch eigene serialisierbare Objekte an. Welche dieser Arten für den Datenpuffer genutzt werden soll, hängt vom Prozess ab: wie soll angezeigt werden, wie soll geändert werden, wie soll sonst noch verarbeitet werden.

    In meinem Beispiel habe ich die Betonung auf Anzeige gelegt und dafür ein DataSet genutzt. Um darin beispielsweise Untergruppe 14.4 zu ändern, muss diese im DataSet gesucht werden, entweder direkt in der Tabelle "Untergruppe" oder über die Tabelle "Gruppe" in deren Childs. Das kann man mit For-Schleifen oder auch mit LinQ machen. Die gefundene DataRow kann dann geändert werden und steht nach dem Speichern des gesamten DataSets als XML-Datei beim nächsten Laden zur Verfügung.

    Für die Alternativen wie XElement kann einfach LinQ to XML und für eigene serialisierbare Objekte kann LinQ to Objects für die Lokalisierung eines Knotens in der XML-Struktur eingesetzt werden.

    Aufwändiger wird es, wenn Du mit einem Parser arbeiten willst. Schau Dir dazu mal XPath an.

    --
    Peter

    Donnerstag, 29. Januar 2015 04:48
  • Wenn die gesamte Datei eingelesen werden soll, dann bieten sich als Datenpuffer ein DataSet, ein XElement oder auch eigene serialisierbare Objekte an. Welche dieser Arten für den Datenpuffer genutzt werden soll, hängt vom Prozess ab: wie soll angezeigt werden, wie soll geändert werden, wie soll sonst noch verarbeitet werden.

    In meinem Beispiel habe ich die Betonung auf Anzeige gelegt und dafür ein DataSet genutzt. Um darin beispielsweise Untergruppe 14.4 zu ändern, muss diese im DataSet gesucht werden, entweder direkt in der Tabelle "Untergruppe" oder über die Tabelle "Gruppe" in deren Childs. Das kann man mit For-Schleifen oder auch mit LinQ machen. Die gefundene DataRow kann dann geändert werden und steht nach dem Speichern des gesamten DataSets als XML-Datei beim nächsten Laden zur Verfügung.

    Hallo Peter,

    <?xml version="1.0" standalone="yes"?>
    <NewDataSet>
      <Gruppe>
        <ID>1</ID>
        <Gruppe>Gruppe1</Gruppe>
      </Gruppe>
      <Gruppe>
        <ID>2</ID>
        <Gruppe>Gruppe2</Gruppe>
      </Gruppe>
      <Gruppe>
        <ID>3</ID>
        <Gruppe>Gruppe3</Gruppe>
      </Gruppe>


      <Untergruppe>
        <ID>69</ID>
        <FK>14</FK>
        <Untergruppe>Untergruppe 14.4</Untergruppe>
        <Wert1>Wert1 69</Wert1>
        <Wert2>69</Wert2>
        <Wert3>75.9</Wert3>
      </Untergruppe>
      <Untergruppe>
        <ID>70</ID>
        <FK>14</FK>
        <Untergruppe>Untergruppe 14.5</Untergruppe>
        <Wert1>Wert1 70</Wert1>
        <Wert2>70</Wert2>
        <Wert3>77</Wert3>
      </Untergruppe>
      <Untergruppe>
        <ID>71</ID>
        <FK>15</FK>
        <Untergruppe>Untergruppe 15.1</Untergruppe>
        <Wert1>Wert1 71</Wert1>
        <Wert2>71</Wert2>
        <Wert3>78.100000000000009</Wert3>
      </Untergruppe

    Du hast es schon richtig verstanden meine ich mal.

    Ich benötige jetzt

       Eingabe: Gruppenamen

    Dann sollte ich als Ergebnis z.B.

     <Untergruppe>Untergruppe 14.4</Untergruppe>
        <Wert1>Wert1 69</Wert1>
        <Wert2>69</Wert2>
        <Wert3>75.9</Wert3>
    

    haben

    Ändere die Werte, schreibe diese zurück.

    Wenn die Datei geladen wird, dann wird es mit den Änderungen anzeigt.

    Grüße Sandra

    Donnerstag, 29. Januar 2015 09:09
  • Hi Sandra,
    ich wiederhole nochmals:

    Eine XML-Datei ist eine sequentielle Datei. Da kann man nicht einfach mal mittendrin etwas ändern. Die Datei muss vollständig gelesen werden und nach der Änderung wieder vollständig zurückgeschrieben werden.

    --
    Peter

    Donnerstag, 29. Januar 2015 21:25
  • Eine XML-Datei ist eine sequentielle Datei. Da kann man nicht einfach mal mittendrin etwas ändern. Die Datei muss vollständig gelesen werden und nach der Änderung wieder vollständig zurückgeschrieben werden.

    Guten Morgen Peter,

    das ist mir schon klar, deshalb frage ich ja nach.

    Ich will die komplette XML Datei einlesen. Danach eine LinQ abfrage starten, nach Eingabe des Gruppennamens.

    Dann habe ich eine Liste oder Array oder ....das Ergebnis.

    <Untergruppe>Untergruppe 14.4</Untergruppe>
       
    <Wert1>Wert1 69</Wert1>
       
    <Wert2>69</Wert2>
       
    <Wert3>75.9</Wert3>

    Jetzt ändere ich die Werte, schreibe die komplette Datei zurück.

    Fragen.

     Welche Klasse (gibt ja viele) eignet sich hierzu am besten? Was würde man da nehmen?

     Was ist up to date. Von früher erinnere ich mich noch mit C++/MFC war das recht kompliziert. XMLDomDocument etc.

    Viele Grüße Sandra

    Freitag, 30. Januar 2015 07:45
  • Hi Sandra,
    wenn der Datenumfang nicht allzu groß ist, kann man die gesamte XML-Datei in den Speicher laden. Wenn Du LinQ to XML nutzen willst ohne Anzeige, dann eignet sich die XElement-Klasse. Beim Laden deserialisiert der Parser die XML-Struktur und legt die Knoten als XElemente ab. Der Rootknoten kann dann wieder gespeichert werden und alle eingebetteten Knoten werden serialisert als XML-File abgelegt. Mit LinQ und entsprechender Where-Bedingung kann eine Menge ermittelt werden, die in Deinem Fall dann den einzigen gefundenen Knoten (XElement) enthält. In diesem Knoten kannst Du alles wie gewünscht ändern und dann den Rootknoten speichern. Damit sind alle Änderungen in der XML-Datei abgelegt. Diese Technolgie eigenet sich aber nicht für die Anzeige der Daten in DataGrids. Da wäre dann ein DataSet besser. Im DataSet kann man filtern und dann die gefundenen DataRows bearbeiten.

    --
    Peter

    Freitag, 30. Januar 2015 09:13
  • Wenn Du LinQ to XML nutzen willst ohne Anzeige, dann eignet sich die XElement-Klasse. Beim Laden deserialisiert der Parser die XML-Struktur und legt die Knoten als XElemente ab. Der Rootknoten kann dann wieder gespeichert werden und alle eingebetteten Knoten werden serialisert als XML-File abgelegt. Mit LinQ und entsprechender Where-Bedingung kann eine Menge ermittelt werden, die in Deinem Fall dann den einzigen gefundenen Knoten (XElement) enthält. In diesem Knoten kannst Du alles wie gewünscht ändern und dann den Rootknoten speichern.

    Hallo Peter,

    sicher, das ist schon klar, dass sich das nicht zur Anzeige eignet.

    Ich will ja intern Berechnungen durchführen, neue ermittelte Werte abspeichern und dann zur Anzeige bringen. Der Bediener muss die Datei dann komplett neu einlesen, laden.

    A) Änderungen durch den Bediener im Grid

    B) Änderungen im Hintergrund

    Evtl. kennst Du ein markantes Beispiel für dieses Vorhaben mit XML/LinQ.

    Und eben dann wie mit den Tools, wie man es heutzutage richtig macht.

    Danke im Voraus und viele Grüße Sandra


    • Bearbeitet Sandra Maier Freitag, 30. Januar 2015 12:11 Format
    Freitag, 30. Januar 2015 12:10
  • Hi Sandra,
    Dein Konzept ist recht unklar.

    Wenn der Bediener die Daten im Grid bearbeiten soll, dann kannst Du doch die Daten gleich im DataSet puffern und auch die Berechnungen mit den Inhalten der DataRows ausführen. Wenn Du typisierte DataSets nutzt, kannst Du auch gleich mit LinQ to Objects zugreifen, um die gewünschten Datensätze zu finden und darin zu ändern. Ohne Abzusüeichern sind die Änderungen auch gleich in der Oberfläche sichtbar. Das DataSet kannst Du dann als XML-Datei abspeichern.

    --
    Peter

    Freitag, 30. Januar 2015 13:57
  • Wenn der Bediener die Daten im Grid bearbeiten soll, dann kannst Du doch die Daten gleich im DataSet puffern und auch die Berechnungen mit den Inhalten der DataRows ausführen. Wenn Du typisierte DataSets nutzt, kannst Du auch gleich mit LinQ to Objects zugreifen, um die gewünschten Datensätze zu finden und darin zu ändern. Ohne Abzusüeichern sind die Änderungen auch gleich in der Oberfläche sichtbar.

    Hallo Peter,

    A) zum Einen soll der Bediener es im Grid ändern können, auch anlegen, löschen, das Übliche halt.

    B) es gibt aber Dateien, die zur Datenhaltungen dienen, der Bediener diese nicht zwingend öffnen muss.

    Sicher, vielleicht geht es einfacher, deshalb frage ich ja;-)

    > kannst Du auch gleich mit LinQ to Objects zugreifen

    Kannst Du das konkretisieren?

    Grüße Sandra

    Freitag, 30. Januar 2015 19:46
  • Hi Sandra,
    da Du unterschiedliche Prozesse betrachtest (unterschiedliche XML-Dateien, einmal zur Bedienung über die Oberfläche, ein anderes Mal zu ausschließlichen Verarbeitung im Background), würde ich auch unterschiedliche Datenpuffer für die unterschiedlichen Prozesse nutzen.

    Zu A) Datagrids

    Zu B) XElements

    Wenn ein typisiertes DataSet genutzt wird, dann kann man auf die Objekte im typisierten DataSet mit LinQ to Objects zugreifen. Das betrifft die Tabellen und die in der Ergebnismenge enthaltenen Datenobjekte, die die DataRows mappen.

    --
    Peter

    Freitag, 30. Januar 2015 21:49
  • Zu B) XElements

    Wenn ein typisiertes DataSet genutzt wird, dann kann man auf die Objekte im typisierten DataSet mit LinQ to Objects zugreifen. Das betrifft die Tabellen und die in der Ergebnismenge enthaltenen Datenobjekte, die die DataRows mappen.

    Hallo Peter,

    wir kommen bald ans Ziel;-)

    Wie würdest Du dann auf das typisierte DataSet mit LinQ to Objects zugreifen um Daten hinzuzufügen, löschen, ändern. Kannst das kurz aufzeigen, dann können wir den Thread bald schließen.

    Viele Grüße Sandra

    Samstag, 31. Januar 2015 11:27
  • Hi Sandra,
    nachfolgend mal ein Beispiel mit typisiertem DataSet, LinQ, Änderung und Rückschreiben. Das typisierte DataSet habe ich mit dem Designer erzeugt und in der XML-Datei ist auch das Schema enthalten.

    using System;
    using System.Data;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
      public partial class Form8 : Form
      {
        public Form8()
        {
          InitializeComponent();
        }
    
        DataGridView dgv1 = new DataGridView() { Dock = DockStyle.Fill };
        DataGridView dgv2 = new DataGridView() { Dock = DockStyle.Fill };
        SplitContainer spc = new SplitContainer() { Dock = DockStyle.Fill };
    
        Form8DataSet ds = new Form8DataSet();
    
        DataTable dtGruppe = new DataTable() { TableName = "Gruppe" };
        DataTable dtUntergruppe = new DataTable() { TableName = "Untergruppe" };
    
        BindingSource bs1;
        BindingSource bs2;
    
        protected override void OnLoad(EventArgs e)
        {
          base.OnLoad(e);
          // Steuerelemente anzeigen
          this.Controls.AddRange(new Control[] { spc });
          this.spc.Panel1.Controls.Add(dgv1);
          this.spc.Panel2.Controls.Add(dgv2);
          // Daten laden
          DataSet ds2 = new DataSet();
          ds2.ReadXml("c:\\temp\\form8.xml");
          ds.Merge(ds2);
    
          //  Bindingsource aufbauen
          this.bs1 = new BindingSource(ds, "Gruppe");
          //this.bs2 = new BindingSource(ds, "Untergruppe");
          this.bs2 = new BindingSource(bs1, "Rel1");
          // Daten binden
          this.dgv1.DataSource = bs1;
          this.dgv2.DataSource = bs2;
          // Datensatz finden, ändern und rückschreiben
          var res = (from itm in ds.Untergruppe 
                     where itm.Untergruppe == "Untergruppe 14.4" 
                     select itm).FirstOrDefault();
          if (res != null) res.Wert3 = DateTime.Now.Millisecond;
          ds.WriteXml("c:\\temp\\form8.xml", XmlWriteMode.WriteSchema);
        }
      }
    }
    
    --
    Peter
    • Als Antwort markiert Sandra Maier Sonntag, 1. Februar 2015 11:31
    Samstag, 31. Januar 2015 17:16
  • Hallo Peter,

    Danke für die Erläuterung. Ich denke wir können den Thread abschließen.

    Letzter Punkt, lokales Dataset ds2

    // Daten laden
           DataSet ds2 = new DataSet();
           ds2.ReadXml("c:\\temp\\form8.xml");
           ds.Merge(ds2);

    Zuweisung zum globalen.

    Macht sicher Sinn, kannst Du die Gründe nennen. Ausgangsfrage aber ja mal beantwortet.

    Ich schließe es somit ab.

    Viele Grüße Sandra


    • Bearbeitet Sandra Maier Sonntag, 1. Februar 2015 11:30 Format
    Sonntag, 1. Februar 2015 11:29
  • Hi Sandra,
    meine XML-Datei ist mit Schema und da gibt es Konflikte beim Laden in das typisierte Dataset. Das kann man mit Merge umgehen.

    --
    Peter

    • Als Antwort markiert Sandra Maier Mittwoch, 4. Februar 2015 14:56
    Sonntag, 1. Februar 2015 18:03