TreeView aus Datenbank füllen - Child-Nodes "Problem"

  • VB.NET

Es gibt 63 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    Ja, ich werd mich damit nun komplett auseinandersetzen. Ich hatte bis Dato z.B. auch noch nix von "Private Shared Function" und "Partial Class" gehört
    das zeigt wieder, wie "mittelalterlich und primitiv" die VBA von Excel läuft. Ich versuch' jetzt zuerst mal das von dir "gebaute" zu verstehen und dann werd ich
    das zu allererst umbauen, dass nicht erst die "einstellungen_treeview" aus der XML gefüllt wird, sondern generell das DataSet sich die Daten aus der Tree.xml zieht
    und dann der Tree gefüllt wird. So wie ich das verstanden hab ist die Struktur und Tabellen ja im DS definiert, Daten an sich sind darin jedoch nicht enthalten.
    Reicht es, die DataTables einmal pro Sitzung zu füllen oder behalten die die Daten nur für den aktuellen Aufruf?

    Also z.B. fülle ich die Tabelle "Tree" mit den Daten aus der XML beim Öffnen der Anwendung, kann ich die in einem späteren Moment (Anwendung bleibt geöffnet), wieder
    aus dem DS abrufen oder muss dann erst wieder die XML eingelesen werden?

    Wollte heute den Tag über schonmal reinschauen und ggf. antworten, allerdings lässt sich das Forum hier leider nicht über ein iPhone bedienen - ich kann
    die Seiten nicht scrollen, egal ob via Firefox oder Safari :(
    Originaler (noch) Nichtskönner :D

    tragl schrieb:

    Also z.B. fülle ich die Tabelle "Tree" mit den Daten aus der XML beim Öffnen der Anwendung, kann ich die in einem späteren Moment (Anwendung bleibt geöffnet), wieder
    aus dem DS abrufen oder muss dann erst wieder die XML eingelesen werden?
    Ich fülle immer das ganze Dataset beim Start der Anwendung.
    Und ich behalte das Dataset auch während der ganzen Laufzeit im Speicher.
    Beim Schliessen frage ich ab, ob Änderungen vorhanden sind, und wenn ja, mache ich den Benutzer darauf aufmerkksam und frage, ob er die Änderungen speichern möchte.
    Zusätzlich habich auch Knöppe zum Speichern wann immer ich will, und zum Neu-Laden, wann immer ich will.
    Das Reload ist ein nettes Feature, wenn man Änderungen gemacht hat, die man dann doch lieber verwerfen möchte. Das Reload setzt die Anwendung dann wieder auf den Zustand des letzten Speicherns zurück.
    Ich nochmal. Der Tree wird mit EdR's Code wie folgt befüllt:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Sub FillTree(tv As TreeView)
    2. tv.Nodes.Clear()
    3. Dim lstNodes As New List(Of TreeRow)
    4. Dim TreeEntries = Dts.Tree.Where(Function(x) x.Freigabe = True).OrderBy(Function(rw) rw.SortKey)
    5. For Each rwTree In TreeEntries
    6. If hasAccess(_userID, rwTree.ID) Then
    7. lstNodes.Add(rwTree)
    8. End If
    9. Next
    10. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing}
    11. For Each rw In lstNodes
    12. Dim iNodes = rw.Nr.Split("."c).Length - 1
    13. If Not nodeCollections(iNodes) Is Nothing Then nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Key}", $"{rw.Nr} = {rw.Bezeichnung}").Nodes
    14. Next
    15. 'tv.ExpandAll()
    16. End Sub


    Gibt's eine einfache Methode, die Root-Nodes in fetter Schrift darzustellen?
    Originaler (noch) Nichtskönner :D
    @tragl Jeder Node hat eine Font-Property.
    Außerdem kannst Du die Nodes OwnerDraw machen, da kannst Du den Text auch farbig reinschreiben.
    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!
    Danke, hab's nun wie folgt eingestellt:

    VB.NET-Quellcode

    1. Public Sub FillTree(tv As TreeView)
    2. tv.Nodes.Clear()
    3. Dim lstNodes As New List(Of TreeRow)
    4. Dim TreeEntries = Dts.Tree.Where(Function(x) x.Freigabe = True).OrderBy(Function(rw) rw.SortKey)
    5. For Each rwTree In TreeEntries
    6. If hasAccess(_userID, rwTree.ID) Then
    7. lstNodes.Add(rwTree)
    8. End If
    9. Next
    10. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing}
    11. Dim boldFont As New Font("Microsoft Sans Serif", 8, FontStyle.Bold)
    12. For Each rw In lstNodes
    13. Dim iNodes = rw.Nr.Split("."c).Length - 1
    14. If Not nodeCollections(iNodes) Is Nothing Then
    15. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Key}", $"{rw.Nr} = {rw.Bezeichnung}").Nodes
    16. If rw.Key Like "*parent*" Then
    17. tv.Nodes(iNodes).NodeFont = boldFont
    18. End If
    19. End If
    20. Next
    21. 'tv.ExpandAll()
    22. End Sub


    allerdings werden leider nicht alle rootnodes fett dargestellt und der Text ist "abgeschnitten"


    mittels owner-drawing zeigt der logischerweise nix mehr an - aber würde ich auch nicht benötigen, fetter text und irgendwann vll mal ein paar Images(Icons) würden vollkommen ausreichen.
    Für owner-drawing fehlt mir auch das Wissen
    Originaler (noch) Nichtskönner :D

    tragl schrieb:

    Für owner-drawing fehlt mir auch das Wissen
    Sieh Dir mal das an:
    TreeViewOwnerDraw.zip
    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!
    @RodFromGermany:

    Hab mich mal ein bisschen umgeschaut wegen ownerdrawing.
    Das Ganze sieht jetzt so aus:


    Die Bold-Darstellung passt nun für alle Nodes, ABER:
    Die Markierung (blauer Kasten) wird nur noch links und unten gezeigt

    Expandiere ich eine Node erscheint die erstmal oben links über der 1. Node - erst wenn ich die 1. selektiere ist das wieder weg.
    Hast du Tipps für mich?

    Achja, ich hab das derzeit so gelöst:
    tv.DrawMode = TreeViewDrawMode.OwnerDrawText

    VB.NET-Quellcode

    1. Private Sub tvMain_DrawNode(sender As Object, e As DrawTreeNodeEventArgs) Handles tvMain.DrawNode
    2. e.DrawDefault = False
    3. Dim boldFont As New Font("Microsoft Sans Serif", 8, FontStyle.Bold)
    4. Dim normalFont As New Font("Microsoft Sans Serif", 8, FontStyle.Regular)
    5. If e.Node.Name Like "*parent_*" Then
    6. TextRenderer.DrawText(e.Graphics, e.Node.Text, boldFont, New Point(e.Node.Bounds.Left, e.Node.Bounds.Top), SystemColors.ControlText, SystemColors.Window)
    7. Else
    8. TextRenderer.DrawText(e.Graphics, e.Node.Text, normalFont, New Point(e.Node.Bounds.Left, e.Node.Bounds.Top), SystemColors.ControlText, SystemColors.Window)
    9. End If
    10. End Sub


    Den Code hab' ich teilweise von hier

    Originaler (noch) Nichtskönner :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „tragl“ ()

    komisch - in dem von dir verlinkten Beispiel wirds true gesetzt.

    Wie dem auch sei

    ErfinderDesRades schrieb:

    du musst natürlich den in e übergebenen Status auswerten, und deine Zeichnung je nachdem anpassen. fiel fergnügen!

    ist ein ziemliches Gefuzzel, ForeColor, BackColor, Selectiert, Unselectiert, und bei deaktiviertem Treeview soll die Selection ja grau.
    Aufs Focus-Rectangle verzichten wir mal.
    tipp: nicht für jeden ZeichenVorgang einen neuen Font erstellen (äh - derzeit sinds sogar zwei)

    ErfinderDesRades schrieb:

    komisch - in dem Beispiel wirds true gesetzt.

    ist richtig, weil er in dem Beispiel einen "eigenen Text" -> in dem Fall den Key der Nodes in anderer Farbe neben den Nodes anzeigen lässt.
    Da brauchts ja den "normalen Zeichenweg" für die Node selbst, der Rest ist dann custom.

    Ich bekomm's leider nich anders hin alle nodes mit "*parent_*" im Key Fett darzustellen, ohne dass der Text hinten abgeschnitten wird.
    Ist jetzt auch kein Beinbruch wenn's nicht geht aber schön wär's trotzdem 8-)
    Originaler (noch) Nichtskönner :D
    @ErfinderDesRades Jou.
    @tragl Werte e.State aus, das ist ein Flag-Enum mit allen Informationen:
    docs.microsoft.com/de-de/dotne…gs.state?view=netcore-3.1
    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!

    tragl schrieb:

    Ich bekomm's leider nich anders hin alle nodes mit "*parent_*" im Key Fett darzustellen, ohne dass der Text hinten abgeschnitten wird.
    Ja, das liegt daran, das der Treeview die Breite der Nodes berechnet aufgrund seines (not bold) Fonts.
    Zum Zeichnen stellt er dann ein Graphics zur Verfügung, was auch nicht breiter ist. Das ist dann für einen bold-font zu klein.
    Man könnte bei TopLevel-Nodes Spaces am NodeText anfügen, damit der TV breitere Graphics bereitstellt.
    OK, manchmal steht man auch einfach auf'm Schlauch.

    Ich hab nun in den Eigenschaften des Trees .Bold = True gesetzt.
    Jetzt wird ja der komplette Tree in Fett dargestellt. Ich hab' mir dann eine Schleife gebaut, die die Nodes, die
    NICHT Like "*parent_*" sind auf normalFont umstellen sollen, allerdings macht er das nur für die Root-Knoten,
    alle andern bleiben unberührt.... Siehe Zeile 17-22

    VB.NET-Quellcode

    1. Public Sub FillTree(tv As TreeView)
    2. tv.Nodes.Clear()
    3. Dim lstNodes As New List(Of TreeRow)
    4. Dim TreeEntries = Dts.Tree.Where(Function(x) x.Freigabe = True).OrderBy(Function(rw) rw.SortKey)
    5. For Each rwTree In TreeEntries
    6. If hasAccess(_userID, rwTree.ID) Then
    7. lstNodes.Add(rwTree)
    8. End If
    9. Next
    10. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}
    11. For Each rw In lstNodes
    12. Dim iNodes = rw.Nr.Split("."c).Length - 1
    13. If Not nodeCollections(iNodes) Is Nothing Then
    14. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Key}", $"{rw.Nr} = {rw.Bezeichnung}").Nodes
    15. End If
    16. Next
    17. Dim normalFont As New Font("Microsoft Sans Serif", 8, FontStyle.Regular)
    18. For Each nd As TreeNode In tv.Nodes
    19. If Not nd.Name Like "*parent_*" Then
    20. nd.NodeFont = normalFont
    21. End If
    22. Next
    23. 'tv.ExpandAll()
    24. End Sub


    Im 1. Bild dürfen 3.1.1 und 3.1.3 entsprechend NICHT bold sein, die Schleife scheint die Nodes aber nicht abzugreifen. Wo ist mein Fehler da?

    Im 2. Bild zu sehen, wie die Keys eingetragen sind. bzw. welche Nodes als "parent_" markiert sind
    Bilder
    • unbenannt2.png

      334,66 kB, 2.541×742, 22 mal angesehen
    Originaler (noch) Nichtskönner :D
    um alle Nodes eines Trees zu erreichen muss man ihn natürlich rekursiv durchlaufen.
    tv.Nodes ist nur die NodeCollection des Treeviews.
    Jeder der Nodes in tv.Nodes hat ja seine eigene NodeCollection.

    In diesem Post ist zB ein rekursiver Durchgang durch Treenodes: TabControl ohne Reiter
    Oder ich kann den Part auch auskopieren:

    VB.NET-Quellcode

    1. Protected Sub OnAfterSelect(e As System.Windows.Forms.TreeViewEventArgs)
    2. Dim recurse As Action(Of TreeNodeCollection) = Sub(nodes As TreeNodeCollection)
    3. For Each nd As TreeNode In nodes
    4. '...
    5. recurse(nd.Nodes) ' Selbst-Aufruf der anonymen Methode
    6. Next
    7. End Sub
    8. recurse(Nodes)
    9. End Sub
    das Prinzip Rekursion (= "Selbst-Aufruf einer Methode") musste dir aber aneignen - dassis Programmer-Basis-Knowhow.
    recherchiere mal auf Wiki - oder ich hab auch mal selbst einen Artikel zu gemacht, aber in einem c#-Forum.
    Spekulatius: Zeile#7 und #8 müssen getauscht werden
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Hab's nun anders lösen können (Zeile 17-23):

    VB.NET-Quellcode

    1. Public Sub FillTree(tv As TreeView)
    2. tv.Nodes.Clear()
    3. Dim lstNodes As New List(Of TreeRow)
    4. Dim TreeEntries = Dts.Tree.Where(Function(x) x.Freigabe = True).OrderBy(Function(rw) rw.SortKey)
    5. For Each rwTree In TreeEntries
    6. If hasAccess(_userID, rwTree.ID) Then
    7. lstNodes.Add(rwTree)
    8. End If
    9. Next
    10. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}
    11. Dim normalFont As New Font("Microsoft Sans Serif", 8, FontStyle.Regular)
    12. For Each rw In lstNodes
    13. Dim iNodes = rw.Nr.Split("."c).Length - 1
    14. If Not nodeCollections(iNodes) Is Nothing Then
    15. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Key}", $"{rw.Nr} = {rw.Bezeichnung}").Nodes
    16. End If
    17. For Each ndc In nodeCollections
    18. If Not ndc Is Nothing Then
    19. For Each nd As TreeNode In ndc
    20. If Not nd.Name Like "*parent_*" Then nd.NodeFont = normalFont
    21. Next
    22. End If
    23. Next
    24. Next
    25. 'tv.ExpandAll()
    26. End Sub


    Wird nun wie gewünscht angezeigt :thumbsup: Auch wenn ich das mit dem recurse nicht in der Umsetzung verstanden hab, war das doch der Geistesblitz der gefehlt hatte..
    Bilder
    • unbenannt.png

      252,76 kB, 301×532, 12 mal angesehen
    Originaler (noch) Nichtskönner :D

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