none
Treeview mit viele Unterknoten RRS feed

  • Frage

  • Hallo

    Ich wollte nachfragen ob es möglich wäre die Unterknoten mit dein Haupt Knotenname zu erstellen.

    Ich habe eine SQLite DB mit diese Spalten

    ID  |  Knotennummer  |  Knotenhauptnummer | Knotenname

    1    |    KNR001          |                                  |   Test01

    2    |    KNR002          |         KNR001              |   Unterknoten01

    3    |    KNR003          |         KNR001              |   Unterknoten02

    4    |    KNR004          |         KNR003              |   Unter Unterknoten01

    5    |    KNR005          |                                   |  Test02

    6    |    KNR006          |         KNR004              |  Unter Unter Unterknoten01

            DB_Verbindung.Open()
            DB_Befehl = DB_Verbindung.CreateCommand
            DB_Befehl.CommandText = "SELECT Knotennummer, Knotenhauptnummer, Knotenname FROM TreeviewDB;"
            Dim sqlreader As System.Data.SQLite.SQLiteDataReader = DB_Befehl.ExecuteReader
            Dim nodeszahl As Integer = 0
            Dim unternoden As String
    
            While sqlreader.Read()
    
                unternoden = sqlreader(0)
    
                If sqlreader(1) = "" Then
                    TreeView1.Nodes.Add(sqlreader(2))
                    TreeView1.Nodes(nodeszahl).Name = sqlreader(0)
                End If
    
                If unternoden = sqlreader(1) Then
                    TreeView1.Nodes(nodeszahl).Nodes.Add(sqlreader(2))
                End If
                nodeszahl = nodeszahl + 1
    
            End While
    
            DB_Verbindung.Close()

    Aber das funktioniert so leider nicht.

    Wie könnte ich diese Sache lösen?

    Mittwoch, 29. Januar 2020 11:42

Antworten

  • Hi,
    ich würde zuerst alle Datensätze einlesen und eine Liste mit TreeNodes erstellen. In einem zweiten Schritt würde ich dann die erzeugten TreeNodes dem TreeView bzw. den übergeordneten Knoten hinzufügen hinzufügen. Diese Technologie hat den Vorteil, dass die Reihenfolge der Einträge in der Datenbank beliebig sein kann, d.h. ein Datensatz für einen Unterknoten kann vor dem Datensatz mit dem übergeordneten Knoten in der Tabelle stehen.

    Hier mal ein Beispiel:

    Public Class Form1
    
      Private tv As New TreeView With {.Dock = DockStyle.Fill}
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(tv)
        Dim nodeList As List(Of MyTreenode) = GetNodes()
        PopulateTreeView(nodeList)
      End Sub
    
      ' DB_Verbindung
      ' DB_Befehl
    
      Private Function GetNodes() As List(Of MyTreenode)
        Dim nodeList As New List(Of MyTreenode)
    
        DB_Verbindung.Open()
        DB_Befehl = DB_Verbindung.CreateCommand
        DB_Befehl.CommandText = "SELECT Knotennummer, Knotenhauptnummer, Knotenname FROM TreeviewDB;"
        Dim sqlreader As System.Data.SQLite.SQLiteDataReader = DB_Befehl.ExecuteReader
        Dim nodeszahl As Integer = 0
        Dim unternoden As String
    
        While sqlreader.Read()
    
          nodeList.Add(New MyTreenode(sqlreader(2).ToString) With {.NodeNummer = sqlreader(0).ToString, .ParentNummer = sqlreader(1).ToString})
    
        End While
    
        DB_Verbindung.Close()
    
        Return nodeList
      End Function
      Private Sub PopulateTreeView(nodeList As List(Of MyTreenode))
        For Each node In nodeList
          If String.IsNullOrEmpty(node.ParentNummer) Then
            tv.Nodes.Add(node)
          Else
            Dim parentnode = nodeList.Find(New Predicate(Of MyTreenode)(Function(n)
                                                                          Return n.NodeNummer = node.ParentNummer
                                                                        End Function))
            parentnode.Nodes.Add(node)
          End If
        Next
      End Sub
    
      Public Class MyTreenode
        Inherits TreeNode
        Public Sub New(text As String)
          MyBase.New(text)
        End Sub
        Public Property NodeNummer As String
        Public Property ParentNummer As String
      End Class
    End Class


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert Mattes80 Mittwoch, 29. Januar 2020 14:37
    Mittwoch, 29. Januar 2020 12:39
  • Hi,
    wenn in der SQL Anweisung ORDER BY steht, dann wird entsprechend sortiert eingelesen und dann auch in dieser Reihenfolge verarbeitet.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert Mattes80 Mittwoch, 29. Januar 2020 14:37
    Mittwoch, 29. Januar 2020 13:46

Alle Antworten

  • Hi,

    was genau funktioniert in welcher Form nicht? Falls nur nicht da gewünschte Ergebnis rauskommt: Wie genau soll das (ausgehend von den geposteten Beispieldaten!) aussehen?


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 29. Januar 2020 11:57
    Moderator
  • Ich weiße jeden Knoten einen Namen zu

    TreeView1.Nodes(nodeszahl).Name = sqlreader(0)

    wie macht man das man unter den Namen einen unterknoten erstellt?

    ich weiß leider nur wie es mit dem Knoten Index geht also so.

    TreeView1.Nodes(nodeszahl).Nodes.Add(sqlreader(2))

    Hier habe ich nun das Problem. Das ist jetzt ein Unterknoten wenn jetzt in der DB noch ein anders Unterknoten dazu kommt geht das schon wieder nicht mehr.

    Daher würde ich gerne die Unterknoten mit dem Hauptknoten.name erstellen.

    Aber ob das überhaupt möglich ist oder wie das geht weiß ich leider nicht.

    Mittwoch, 29. Januar 2020 12:06
  • Hi,
    ich würde zuerst alle Datensätze einlesen und eine Liste mit TreeNodes erstellen. In einem zweiten Schritt würde ich dann die erzeugten TreeNodes dem TreeView bzw. den übergeordneten Knoten hinzufügen hinzufügen. Diese Technologie hat den Vorteil, dass die Reihenfolge der Einträge in der Datenbank beliebig sein kann, d.h. ein Datensatz für einen Unterknoten kann vor dem Datensatz mit dem übergeordneten Knoten in der Tabelle stehen.

    Hier mal ein Beispiel:

    Public Class Form1
    
      Private tv As New TreeView With {.Dock = DockStyle.Fill}
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(tv)
        Dim nodeList As List(Of MyTreenode) = GetNodes()
        PopulateTreeView(nodeList)
      End Sub
    
      ' DB_Verbindung
      ' DB_Befehl
    
      Private Function GetNodes() As List(Of MyTreenode)
        Dim nodeList As New List(Of MyTreenode)
    
        DB_Verbindung.Open()
        DB_Befehl = DB_Verbindung.CreateCommand
        DB_Befehl.CommandText = "SELECT Knotennummer, Knotenhauptnummer, Knotenname FROM TreeviewDB;"
        Dim sqlreader As System.Data.SQLite.SQLiteDataReader = DB_Befehl.ExecuteReader
        Dim nodeszahl As Integer = 0
        Dim unternoden As String
    
        While sqlreader.Read()
    
          nodeList.Add(New MyTreenode(sqlreader(2).ToString) With {.NodeNummer = sqlreader(0).ToString, .ParentNummer = sqlreader(1).ToString})
    
        End While
    
        DB_Verbindung.Close()
    
        Return nodeList
      End Function
      Private Sub PopulateTreeView(nodeList As List(Of MyTreenode))
        For Each node In nodeList
          If String.IsNullOrEmpty(node.ParentNummer) Then
            tv.Nodes.Add(node)
          Else
            Dim parentnode = nodeList.Find(New Predicate(Of MyTreenode)(Function(n)
                                                                          Return n.NodeNummer = node.ParentNummer
                                                                        End Function))
            parentnode.Nodes.Add(node)
          End If
        Next
      End Sub
    
      Public Class MyTreenode
        Inherits TreeNode
        Public Sub New(text As String)
          MyBase.New(text)
        End Sub
        Public Property NodeNummer As String
        Public Property ParentNummer As String
      End Class
    End Class


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert Mattes80 Mittwoch, 29. Januar 2020 14:37
    Mittwoch, 29. Januar 2020 12:39
  • Super danke

    noch eine Frage wie kann man diese jetzt nach ABC sortieren lassen?

    Mittwoch, 29. Januar 2020 13:36
  • Hi,
    wenn in der SQL Anweisung ORDER BY steht, dann wird entsprechend sortiert eingelesen und dann auch in dieser Reihenfolge verarbeitet.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert Mattes80 Mittwoch, 29. Januar 2020 14:37
    Mittwoch, 29. Januar 2020 13:46
  • Super Danke es geht.

    Jetzt habe ich noch eine Frage.

    Wäre es auch möglich das ganze in einer ComboBox so auszulesen?

    Mittwoch, 29. Januar 2020 13:53
  • Hi,
    natürlich kann das möglich sein, wenn der Programm-Algorithmus klar ist. Eine Combobox hat mit hierarchischen Daten normalerweise nichts zu tun.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Mittwoch, 29. Januar 2020 13:58
  • Ich habe mir es so gedacht beim erstellen eines neuen Knoten das man in der Tooltrip auf den Button klickt.

    und da ein anderes Form öffnet in diesen Form ist dann ein Textbox um den Namen des Knoten einzutragen.

    und wenn es ein unterknoten sein soll, dann ist ein Combobox da um den Hauptknoten auszuwählen.

    Bei Combobox kenne ich leider nur diesen Befehl

    ComboBox1.Items.add(Knoten)

    Aber so listet er mir alle untereinander auf wenn dann würde ich gerne auch so sortiert haben wollen.

    Hauptknoten 1 

    --unterknoten

    ----unter unterknoten

    Hauptknoten 2

    usw.

    Leider habe ich keine Idee und Vorstellung wie man sowas in Code umsetzen kann.

    Kannst du mir Bitte ein Code beispiel geben?

    Mittwoch, 29. Januar 2020 14:13
  • Hi,
    für jede Ebene muss da eine CombvoBox her. Das kann recht unhandlich werden und auch für den Bediener nicht besonders intuitiv. Besser kann es sein, mit einem Rechtsklick auf einen Knoten im TreeView ein Kontextmenü öffnen mit neu, löschen usw.

    Primär sollte die Bedientechnologie sein.


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Mittwoch, 29. Januar 2020 14:23
  • Ich habe eine Frage

    Wie kann ich wenn ich auf Rechtsklick mache diese .NodeNummer den Inhalt auslesen?



    Mittwoch, 29. Januar 2020 17:17
  • Hi,
    nachfolgend mal eine kleine Demo zu Deiner Frage. Mangels einer passenden Datenbank habe ich den Datenbankzugriff auskommentiert und dafür eine Zufallslösung eingebaut.

    Public Class Form1
    
      Private WithEvents tv As New TreeView With {.Dock = DockStyle.Fill}
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(tv)
        Dim nodeList As List(Of MyTreenode) = GetNodes()
        PopulateTreeView(nodeList)
      End Sub
    
      ' DB_Verbindung
      ' DB_Befehl
    
      Private Function GetNodes() As List(Of MyTreenode)
        Dim nodeList As New List(Of MyTreenode)
    
        'DB_Verbindung.Open()
        'DB_Befehl = DB_Verbindung.CreateCommand
        'DB_Befehl.CommandText = "SELECT Knotennummer, Knotenhauptnummer, Knotenname FROM TreeviewDB;"
        'Dim sqlreader As System.Data.SQLite.SQLiteDataReader = DB_Befehl.ExecuteReader
        'Dim nodeszahl As Integer = 0
        'Dim unternoden As String
    
        'While sqlreader.Read()
    
        '  nodeList.Add(New MyTreenode(sqlreader(2).ToString) With {.NodeNummer = sqlreader(0).ToString, .ParentNummer = sqlreader(1).ToString})
    
        'End While
    
        'DB_Verbindung.Close()
    
        Dim rnd As New Random
        For i = 1 To 100
          Dim parent As String = ""
          If i > 2 AndAlso rnd.NextDouble < 0.5 Then parent = "KNR" & rnd.Next(1, i - 1).ToString("000")
          nodeList.Add(New MyTreenode($"Node {i}") With {.NodeNummer = $"KNR{i:000}", .ParentNummer = parent})
        Next
    
        Return nodeList
      End Function
      Private Sub PopulateTreeView(nodeList As List(Of MyTreenode))
        For Each node In nodeList
          If String.IsNullOrEmpty(node.ParentNummer) Then
            tv.Nodes.Add(node)
          Else
            Dim parentnode = nodeList.Find(New Predicate(Of MyTreenode)(Function(n)
                                                                          Return n.NodeNummer = node.ParentNummer
                                                                        End Function))
            parentnode.Nodes.Add(node)
          End If
        Next
      End Sub
    
      Private Sub tv_NodeMouseClick(sender As Object, e As TreeNodeMouseClickEventArgs) Handles tv.NodeMouseClick
        Dim node = TryCast(e.Node, MyTreenode)
        If node IsNot Nothing AndAlso e.Button = MouseButtons.Right Then MsgBox(node.NodeNummer)
      End Sub
    
      Public Class MyTreenode
        Inherits TreeNode
        Public Sub New(text As String)
          MyBase.New(text)
        End Sub
        Public Property NodeNummer As String
        Public Property ParentNummer As String
      End Class
    End Class


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Mittwoch, 29. Januar 2020 17:59
  • Super danke

    jetzt hab ich das bei Selected probiert geht das hier anders?

    bei Selected geht das irgendwie nicht


    TreeView1.SelectedNode.NodeNummer

    da gibt das NodeNummer nicht

    Mittwoch, 29. Januar 2020 19:55
  • Hi,
    SelectedNode gibt einen Verweis vom Type TreeNode zurück, egal, ob das betreffende Objekt vom Typ TreeNode oder einer von TreeNode geerbten Klasse ist. In meinem Beispiel wird anstelle TreeNode die von TreeNode geerbte Klasse MyTreeNode genutzt. In der Klasse TreeNode gibt es die Eigenschaft NodeNummer nicht, erst in der geerbten Klasse MyTreeNode. Um bei SelectedNodel auf die Eigenschaft NodeNummer der Klasse MyTreeNode zuzugreifen, muss dem Compiler bzw. die Laufzeitumgebung mitgeteilt werden, dass anstelle eines Verweises vom Typ TreeNode der Verweis vom Typ MyTreeNode genutzt werden soll. Das funktioniert, weil MyTreeNode von TreeNode erbt. Für die "Umbiegung" des Types für den Zugriff wird Typcasting genutzt, wie CType oder TryCast.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Donnerstag, 30. Januar 2020 06:03
  • Hallo

    unter MyTreenode kann ich aber kein SelectedNode oder NodeNummer nicht finden. 

    Wie mach ich das Verweiß das ich es dann finden kann?

    Donnerstag, 30. Januar 2020 07:28
  •     Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            Dim node = TryCast(sender.node, MyTreenode)
    
            MsgBox(node.NodeNummer)
        End Sub

    Da bekomme ich leider die Fehlermeldung

    System.MissingMemberException: "Der öffentliche Member node für den Typ Button wurde nicht gefunden."

    Donnerstag, 30. Januar 2020 08:09
  • hab das jetzt mal so gelöst

        Private Sub TreeView1_NodeMouseClick(sender As Object, e As TreeNodeMouseClickEventArgs) Handles TreeView1.NodeMouseClick
            Dim node = CType(e.Node, MyTreenode)
            MsgBox(node.NodeNummer)
        End Sub

    statt den MsgBox speichere ich das dann in einer Variable so wurde es dann auch gehen.

    Über eine andere Lösung wäre ich dankbar. 

    Donnerstag, 30. Januar 2020 10:29