Announcement

Collapse
No announcement yet.

Wie erzeuge ich ein TreeView mit beliebig tiefer Verschachtelung?

Collapse
This topic is closed.
X
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Wie erzeuge ich ein TreeView mit beliebig tiefer Verschachtelung?

    Hallo zusammen,

    ich habe folgendes Problem: in einer Datenbank gibt es eine Tabelle mit Daten, die ich in einem TreeView darstellen möchte. Jeder Datensatz hat eine eindeutige ID und falls es sich um ein Child eines anderen Datensatzes handelt, eine ParentID in der die ID des parents - wie der Name schon sagt - gespeichert ist.

    Beispiel:

    * ID - Name - ParentID
    * 1 - Test1 - NULL
    * 2 - A - 1
    * 3 - B - 1
    * 4 - C - 3 usw.

    Diese Daten lese ich aus und möchte ich dann programmatisch dem TreeView im Page_Load einer Seite zuweisen. Ansich klappt das auch soweit. Ich habe allerdings das Problem, dass die Verschachtelungstiefe des TreeViews völlig von der Verschachtelungstiefe in meinem Code abhängt. Ich möchte die Tiefe jedoch eigentlich völlig offen lassen, sodass es z.B. keine oder nur eine Ebene geben kann, aber beispielsweise auch 30, wenn's sein muss.

    Mein Code dazu:
    Code:
    protected void Page_Load(object sender, EventArgs e)
        {
            // TODO: TreeView mit Zielen füllen
            if (!IsPostBack)
            {
                int eId = (int)Session["eId"];
                List<Ziel> zielList = ZielProvider.GetAllZielWithRelationData(eId);
                foreach (Ziel evalZiel in zielList)
                {
                    if (evalZiel.Parent == null)
                    {
                        TreeNode newNode = new TreeNode(evalZiel.Name.ToString());
                        this.TreeViewZiele.Nodes.Add(newNode);
                        List<Ziel> childList0 = ZielProvider.GetAllZielByParent(evalZiel.Id);
                        foreach (Ziel childZiel0 in childList0)
                        {
                            TreeNode childNode0 = new TreeNode(childZiel0.Name.ToString());
                            newNode.ChildNodes.Add(childNode0);
                            List<Ziel> childList1 = ZielProvider.GetAllZielByParent(childZiel0.Id);
                            foreach (Ziel childZiel1 in childList1)
                            {
                                TreeNode childNode1 = new TreeNode(childZiel1.Name.ToString());
                                childNode0.ChildNodes.Add(childNode1);
                            }
                        }
                    }
                }
            }
        }
    Man sieht schnell, dass es hier nur einen Parent geben kann, der maximal zwei Ebenen darunter haben kann, dann ist Ende. Ich könnte das auch noch weiter führen, aber das wäre dann doch ziemlich unschön denke ich, außerdem wäre die Tiefe eben immer fest vorgegeben...

    Gibt es da eine einfachere Möglichkeit dies zu lösen?

    Danke im Voraus,

    Jessica

  • #2
    Hallo und willkommen im Forum,

    damit keine starre Tiefe vorgegeben ist kann ein rekursiver Ansatz verwendet werden.

    Grob und eher pseudocodemäßig schaut das dann so aus:
    [highlight=c#]
    protected void Page_Load(object sender, EventArgs e)
    {
    if (!IsPostBack)
    {
    // ...
    ErstelleTreeView(rootNode, StartElement);
    // ...
    }
    }

    // Rekursiver Aufbau
    private void ErstelleTreeView(TreeViewNode, ParentNode)
    {
    foreach (ChildElement child in ParentNode.Children)
    {
    TreeNode = new (...);
    TreeViewNode.Add(TreeNode);

    // Rekursion:
    if (child.Children > 0)
    ErstelleTreeView(TreeNode, child);
    }
    }
    [/highlight]


    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Ich schreibs mal exemplarisch hin:

      1. Hole alle Datensätze aus Datenbank
      2. Für jeden Datensatz in Datensätzen
      3. Hat aktueller Datensatz einen Datensatz?
      4. Nein, Füge ihn als Rootknoten hinzu - lösche den Datensatz aus deinen Datensätzen
      5. Ja, Gibt es einen Knoten der die ParentId hat
      6. Nein, ignoriere Datensatz vorerst
      7. Ja, Hänge den Knoten als Child an - lösche den Datensatz aus deinen Datensätzen
      8. Fang wieder bei 2 an

      So wird nach und nach der Baum aufgebaut und die Liste geleert. Ist nicht ober turbo performant, aber hierbei kommt es auch sehr stark auf die größe des Baums an.
      ösche den Datensatz aus deinen Datensätzen
      8. Fang wieder bei 2 an

      So wird nach und nach der Baum aufgebaut und die Liste geleert. Ist nicht ober turbo performant, aber hierbei kommt es auch sehr stark auf die größe des Baums an.

      "lösche den Datensatz aus deinen Datensätzen" heisst natürlich nicht in der DB löschen, sondern clienseitig aus der Liste der noch einzufügenden Knoten herausnehmen.

      Comment


      • #4
        [Edit: o.o" ups... in der Zeit, in der ich das hier geschrieben hab, haben nun doch welche von euch geantwortet ^^" aber die Ansätze sehen ja recht ähnlich aus ]

        Hm, ich bin mittlerweile einen Schritt weiter zugegebenermaßen aber nicht ohne einen Tipp aus einem anderen Forum

        Meine vorläufige Lösung sieht so aus:
        Code:
            protected void Page_Load(object sender, EventArgs e)
            {
                // TODO: TreeView mit Zielen füllen
        
                if (!IsPostBack)
                {
                    int eId = (int)Session["eId"];
        
                    List<Ziel> zielList = ZielProvider.GetAllZielWithRelationData(eId);
        
                    foreach (Ziel evalZiel in zielList)
                    {
                        if (evalZiel.Parent == null)
                        {
                            TreeNode newNode = new TreeNode(evalZiel.Name.ToString());
                            this.TreeViewZiele.Nodes.Add(newNode);
                            LoadChildNodes(evalZiel.Id, newNode);
                        }
        
                    }
                }
            }
        
            protected void LoadChildNodes(int parentId, TreeNode parentNode)
            {
                List<Ziel> childList = ZielProvider.GetAllZielByParent(parentId);
                foreach (Ziel childZiel in childList)
                {
                    TreeNode childNode = new TreeNode(childZiel.Name.ToString());
                    parentNode.ChildNodes.Add(childNode);
        
                    LoadChildNodes(childZiel.Id, childNode);
                }
            }
        Allerdings würde mich jetzt noch eines interssieren: hinter jedem Aufruf von LoadChildNodes steckt jetzt eine Datenbankabfrage, um die jeweiligen Kindelemente zu kriegen (ZielProvider.GetAllZielByParent). Bei einer geringen Verschachtelung sollte das noch kein Problem darstellen, aber sobald diese tiefer wird, entstehen natürlich immer mehr Datenbankabfragen, was die Sache schätzungsweise extrem verlangsamt.

        Gäbe es hierfür vielleicht noch eine bessere Lösung?

        Comment


        • #5
          Hallo,

          du kannst dir ja alle Daten entsprechend dem Schema deinen Eingangsposts vom Server holen -> die Daten sind lokal vorhanden und dort können die jeweiligen Abfragen direkt im RAM durchgeführt werden.

          Es ist also nur 1 DB-Abfrage notwendig.


          mfG Gü
          "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

          Comment


          • #6
            Möglicherweise steh ich grad etwas auf der Leitung, aber... wie genau meinst du das?
            Ich wüsste jetzt leider nicht auf Anhieb, wie ich da ansetzen sollte

            Comment


            • #7
              Bitte keine heimlichen Crossposts. Warum siehe hier.

              Comment


              • #8
                So heimlich war das eigentlich garnicht ^^" ich hab ja darauf hingewiesen, dass die Lösung durch jemanden aus einem anderen Forum entstanden ist.
                Deswegen poste ich ja auch Ergebnisse, wenn irgendwo welche entstehen. Kam nur leider fast zeitgleich mit den andren Posts ^^"

                Comment


                • #9
                  Generell sollte man GLEICH sagen, dass man in 2 Foren gepostet. Nicht erst wenn irgendwelche Lösung diskutieren. Dann können sich sämtliche Leute die sich hier die Mühe machen Dir zu antworten auf EINE Diskussion berufen und man muss nicht 30 mal das gleiche diskutieren.

                  Comment

                  Working...
                  X