VB.net - TreetView mit allen Knoten auslesen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von sascha_10.

    VB.net - TreetView mit allen Knoten auslesen

    Hallo zusammen,

    ich hab viel im Netz gesucht und einiges ausprobiert. Leider habe ich nichts gefunden, wie man einen kompletten Treetview in einer MSSQL speichern kann und wieder in der Form einlesen kann.

    Die Braumstruktur hat mehrere Unterknoten, wo ich immer hängen bleibe:
    • Hauptknoten 1
      • ---> Unterknoten 1
      • Wert 1
      • Wert 2
      • Wert x
        • ---> Unterknoten 2
        • Wert 1
        • Wert 2
        • Wert x
          • ---> Unterknoten x
          • Wert x
    • Hauptknoten 2
      • ---> Unterknoten 1
      • Wert 1
      • Wert 2
        • ---> Unterknoten 2
          • Wert 1
          • Wert 2
    • Hauptknoten 3
    • Hauptknoten x
    • Wert 1
    • Wert 2
    Wäre super, wenn jemand ein Code-Beispiel hat.

    Vor allem wäre es mir wichtig, wie man die Struktur so auslesen kann, dass ich jede Position kennen (x,y) und diese danach wieder zusammenbauen kann.

    Vielen Dank für eure Hilfe.

    Gruß
    Sascha :D
    @sascha_10 Mach Dir eine rekursive Methode, der der Knoten übergeben wird.
    Hat der Knoten Unterknoten, ruf diese rekursive Methode auf,
    wenn nicht, lies die relevante Property aus und gehe zum nächsten Knoten.
    Hast Du den letzten Knoten erreicht, bist Du feddich;
    ruf die rekursive Methode auf.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    mit der "MSSQL" meinst du vermutlich eine Datenbank.
    In ein Form einlesen kann man eine Baumstruktur gar nicht. Datenbank-Daten kannste in ein typisiertes Dataset einlesen.

    Da gibt es zwei möglichkeiten, Bäume in einer DB zu persistieren:
    1. mit einer Relation der tabelle auf sich selbst
      Hierbei musste die komplette Tabelle in ein typDataset einlesen, und dann kannste mit RFGs rekursive Methode bearbeiten
    2. mit sog. "NestedSets"
      Dabei müssen die Node-Ids sortiert sein, und jeder Node gibt die Anzahl seiner ChildNodes an.
      Ist vonne DatenVerwaltung her aufwändig, insbesondere das Umstrukturieren.
      Dafür kann man aber auch Teilbäume abrufen.
    Ein Code-Sample wird dir niemand geben können - es hat ja keiner deine MSSQL
    Da gibt's im Netz kilometerlange Diskussionen, wie ein Tree in SQL dargestellt werden kann.
    Die gebräuchlichsten
    1) Adjancency List
    Jeder Node hat einen Parent Node (Null bei root)
    Einfachste Variante, wird aber langsam bei sehr vielen Nodes

    2) Nested Sets
    wie @ErfinderDesRades schon schrieb, wird es aufwändig, wenn sich der Baum verändert.

    3) Closure Table
    Hält die Verbindungen in einer gesonderten Tabelle.
    Aufwändiger im Design, aber schnell in allen Abfragen und bei Veränderungen.

    @sascha_10: Wie groß werden deine Bäume sein?
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hallo zusammen,

    vielen Dank für die Rückmeldung.

    @petaod
    Die tiefe der Unterknoten wird zwischen 3-7 Unterknoten sein.
    Die Hauptknoten, vermutlich um die 50 Stück.

    @RodFromGermany
    Wie funktioniert die Closure Table?
    Wie funktioniert die rekursive Methode?

    @ErfinderDesRades
    Mir geht es weniger um die Datenbank, sondern um die Werte mit mehreren Ebenen in einem Treeview aufzubauen.
    Wenn du hier ein gutes Beispiel hast, würde es mir reichen.

    Vielen DAnk

    VG

    Sascha

    sascha_10 schrieb:

    Wie funktioniert die rekursive Methode?
    Prinzipiell so was:

    VB.NET-Quellcode

    1. Function RekursiveMethode(ByRef parameter As Integer) As Boolean
    2. If parameter > 10 Then ' Abbruchbedingung
    3. Return False
    4. End If
    5. parameter += 1
    6. Return True
    7. End Function
    Die andere Frage war nicht an mich
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    ich verstehe nicht ganz was du willst?
    du lädst Daten aus einer MsSql Datenbank, wird denn alles richtig geladen (mit Unterknoten)?

    du sagst es geht dir nur um die Werte.
    hier eine Variante auszulesen un in eine TextDatei die Werte zuschreiben.

    VB.NET-Quellcode

    1. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    2. SaveTreeViewIntoFile("D:\TreeText.txt", TreeView1)
    3. End Sub
    4. Private Sub WriteNodeIntoString(ByVal level As Integer, ByVal node As TreeNode, ByVal sb As StringBuilder)
    5. sb.AppendLine(New String(ControlChars.Tab, level) + node.Text)
    6. For Each child As TreeNode In node.Nodes
    7. WriteNodeIntoString(level + 1, child, sb)
    8. Next child
    9. End Sub
    10. Private Sub SaveTreeViewIntoFile(ByVal file_name As String, ByVal trv As TreeView)
    11. Dim sb As New StringBuilder()
    12. For Each node As TreeNode In trv.Nodes
    13. WriteNodeIntoString(0, node, sb)
    14. Next node
    15. File.WriteAllText(file_name, sb.ToString())
    16. End Sub


    schaumal ob du damit was anfangen kannst

    Kasi schrieb:

    hier eine Variante auszulesen un in eine TextDatei die Werte zuschreiben.
    Hmm - das Auslesen fehlt aber.
    Achso - du meinst den tv auslesen.
    Ich dachte, man muss dann aber auch die Datei einlesen, und daraus den TV wieder aufbauen können.

    Ich hab mal nach "TreeviewfromFile" inne Forensuche gesucht, fand dieses: Treeview & Pfade
    selbst jetzt nochmal reingeguckt habich nicht.

    jetzt doch reingeguckt - trifft das Thema nicht so gut.

    jetzt im Anhang was von meine Platte. Das Speichern funzt nach demselben Prinzip wie von Kasi gezeigt (zu jedem Node den Level mitgeben).
    Das Einlesen von sowas ist aber trickiger, als das wegschreiben.
    frmTreeSaver

    VB.NET-Quellcode

    1. Imports System.Windows.Forms
    2. Imports System.IO.Ports
    3. Imports System.Drawing
    4. Imports System.IO
    5. Public Class frmTreeSaver
    6. Private _DataFile As String = Path.GetFullPath("..\..\TreeData.txt")
    7. Public Sub New()
    8. InitializeComponent()
    9. TV.ExpandAll()
    10. End Sub
    11. Private Shared Sub Save(nodes As TreeNodeCollection, dataFile As String)
    12. ' zu jedem Node wird sein Level mit-gespeichert
    13. Dim level = 0
    14. Using sw = New StreamWriter(dataFile)
    15. Dim recurse As Action(Of TreeNodeCollection) = Sub(nds)
    16. level += 1
    17. For Each nd As TreeNode In nds
    18. sw.WriteLine($"{level} {nd.Text}")
    19. recurse(nd.Nodes)
    20. Next
    21. level -= 1
    22. End Sub
    23. recurse(nodes)
    24. End Using
    25. End Sub
    26. Private Shared Sub Reload(nodes As TreeNodeCollection, dataFile As String)
    27. 'vom Stack immer runterpoppen bis ziel-level. Dann neuen Node erzeugen und seine TreenodeCollection draufpushen
    28. nodes.Clear()
    29. Dim stk = New Stack(Of TreeNodeCollection)({nodes})
    30. For Each line In File.ReadAllLines(dataFile)
    31. Dim splts = line.Split({" "c}, 2)
    32. Dim level = Integer.Parse(splts(0))
    33. While stk.Count > level : stk.Pop() : End While
    34. stk.Push(stk.Peek.Add(splts(1)).Nodes)
    35. Next
    36. End Sub
    37. Private Sub AnyButton_Click(sender As Object, e As EventArgs) Handles btLoad.Click, btSave.Click, btClear.Click
    38. Select Case True
    39. Case sender Is btLoad : TV.BeginUpdate() : Reload(TV.Nodes, _DataFile) : TV.ExpandAll() : TV.EndUpdate()
    40. Case sender Is btSave : Save(TV.Nodes, _DataFile)
    41. Case sender Is btClear : TV.Nodes.Clear()
    42. End Select
    43. End Sub
    44. End Class
    Hihi - besonders Zeile #39 ist eine Herausforderung, weil verwendet drei Methoden in einer Zeile, die wohl alle recht unbekannt sind, und nachzugucken sind - will man da was verstehen.
    Das Nachgucken ist ein Kinderspiel, wenn man weiss wie - vlt. so: Video-Tut: Welchen Datentyp hat das Objekt?
    Und wenn mans genauer wissen will, den ObjectBrowser bemühen: VisualStudio richtig nutzen (Google ist nicht deine Mami)
    Es lohnt sich: Anschliessend kann man mit Treeview besser umgehen, und wer mit Rekursion zu tun hat, sollte Stack auch kennen.
    Dateien
    • TreeSaver.zip

      (14,81 kB, 69 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hallo zusammen,

    vielen Dank. Damit hab ich es geschafft, meine Struktur anzupassen.
    Speichern und auslesen aus der Datenbank funktioniert perfekt.

    Hab den Code von @ErfinderDesRades genutzt. Danke dir.

    Ich habe trotzdem noch eine Frage:
    Wie kann ich die Farbe (ForeColor) noch ändern?

    VB.NET-Quellcode

    1. Dim level = Integer.Parse(reader.GetAttribute("Level"))
    2. While stk.Count > level : stk.Pop() : End While
    3. stk.Push(stk.Peek.Add(reader.GetAttribute("ID"), reader.GetAttribute("VALUE")).Nodes)


    Dann wäre soweit alles super.

    Vielen Dank und einen schönen Abend

    Viele Grüße
    Sascha
    Die Farbe (ForeColor) ändert man so:

    VB.NET-Quellcode

    1. ForeColor = andereColor
    Sinnvolleres kann ich nicht angeben, ich weiss nicht von wem die ForeColor, und wo du die andereColor herholen willst, und welchen Datentyp diese Color-Dinger überhaupt haben.
    Ich weiss nur: Sie müssen denselben Datentyp haben.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Die Zuweisung der Farbe ist Allgemein kein Problem.

    Nur gerade hier, wo ich die Zeile einfüge, hänge ich noch fest. Wo ich die Farbe mit dazugeben kann.

    VB.NET-Quellcode

    1. stk.Push(stk.Peek.Add(reader.GetAttribute("ID"), reader.GetAttribute("VALUE")).Nodes)


    Also der Reader ist nicht das Problem. Bekomme auch die einfache Farbe x.ForeColor = Color.Red nicht zugefügt.