Treeview, Selektiertes TreeNode an 1. Position anzeigen

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

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Michl.

    Treeview, Selektiertes TreeNode an 1. Position anzeigen

    Hallo zusammen,

    ich ein Problem mit der Darstellung eines via Code selektierten TreeNodes.

    Ich habe 2 TreeViews mit identischem Aufbau.
    Wenn ich im 1. TreeView einen Eintrag selektiere, wird dieser TreeNode (gleicher Name, aber anderer Text) im 2. TreeView Fett markiert. Soweit so gut.

    Ich selektiere mit

    VB.NET-Quellcode

    1. Dim tn = tvAblagen.Nodes.Find(CStr(tvLagerorte.SelectedNode.Name), True)
    2. If Not tn.Count = 1 Then Return
    3. tvAblagen.SelectedNode = tn(0)

    eine TreeNode und setze diesen Eintrag danach auf 'Bold' zur leichteren Erkennung.

    Verwende ich "Ensure Visible", wird der Eintrag zwar im 2. TreeView im sichtbaren Bereich angezeigt, aber leider nicht genau gegenüber dem Eintrag im 1. TreeView.

    Meine Idee wäre, beide Einträge nach der Selektion am oberen Rand des TreeViews anzuzeigen.

    Ich habe bisher noch keine Möglichkeit gefunden eine TreeNode so zu positionieren, dass sie oben als erster Eintrag angezeigt wird.

    Kennt ihr hier eine Lösung, und könnt Ihr mir da weiterhelfen?

    Vorab vielen Dank und viele Grüße,
    Michl

    Michl schrieb:

    Wenn ich im 1. TreeView einen Eintrag selektiere, wird dieser TreeNode (gleicher Name, aber anderer Text) im 2. TreeView Fett markiert.
    Ist diese Koppelung sinnvoll?
    Du zeigst in beiden TreeViews dieselbe Instanz an.
    Wenn das nicht sein soll, musst Du die zweite Instanz clonen.
    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!
    @Michl:
    Du könntest zuerst den letzten Knoten eines jeden TreeViews per EnsureVisible erfassen, und dann jeweils nochmal den gewünschten Knoten.
    Musst aber den bei mir beliebten Delay-Workaround verwenden, sonst klappt es nicht.

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    3. Await Threading.Tasks.Task.Delay(1)
    4. TreeView1.Nodes(IndexDesGewünschtenNodes).EnsureVisible()
    5. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    Moin RFG,

    Hierbei handelt es sich um 2 verschiedene Instanzen. Die Daten kommen aus 2 verschiedenen Datenlagen. Der Name der Nodes ist zwar gleich aber der Text und andere Eigenschaften eben nicht.
    Es gibt bestimmt auch andere Darstellungsmöglichkeiten. Ich habe diese für mich gewählt, weil ich die Baumstruktur benötige und es für mich eine gute Zugehörigkeit der Items darstellt wenn sie sich korrekt gegenüber stehen.

    Ich hänge mal eine Abbildung mit an.
    (Links sind Langnamen zu sehen, auch in sonstigen Übersichten zu sehen sind. Rechts, zugehörige Kurzbezeichnungen, die ich für interne Zwecke benötige (diese sind in edierbar))

    viele Grüße, Michael
    Bilder
    • Treeviews.png

      42,94 kB, 615×497, 42 mal angesehen

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

    Hallo VaporiZed,

    Ich habe das Beispiel von dir einmal versucht umzusetzen.

    Als Ergebnis habe ich, dass in beiden TV der selektierte Eintrag korrekt gegenüberstehend angezeigt wird. :thumbup:

    Keines Manko: Die selektierten Einträge werden ganz unten im TV angezeigt und nicht oben, on Top.

    Ich warte mal noch etwas ab, ob hier noch weitere Ideen reinkommen. Wenn nicht, kann ich mit dieser Lösung erst einmal ganz gut leben :)

    Gruß, Michl

    Michl schrieb:

    Die selektierten Einträge werden ganz unten im TV angezeigt und nicht oben
    EnsureVisible() bedeutet, dass sie ühaupt angezeigt werden, nicht aber, dass sie ganz oben angezeigt werden. :/
    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!
    Das kann ich grad nicht nachvollziehen. Der erste Befehl zeigt den letzten Knoten, also wird das TreeView nach ganz unten gescrollt. Danach wird nach einer kurzen Latenz der gewünschte Knoten per EnsureVisible eingescrollt, was häufig dazu führt, dass der Knoten ganz oben steht. Klar, wenn er einer der letzten im TV ist, ist das Vorhaben nie umsetzbar, da kann der gewünschte Knoten nie ganz oben stehen. Aber das muss ja dann auch nicht.
    Hier mein Beispiel. Ich habe ein TV mit 10 Knoten. Ich will Knoten3 ganz oben haben. Dazu der Code und das Ergebnis in Bildern.

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    3. Await Threading.Tasks.Task.Delay(1)
    4. TreeView1.Nodes(3).EnsureVisible()
    5. End Sub


    Hab grad festgestellt, dass es wohl auch ohne DelayWorkaround geht, bin mir aber nicht ganz sicher, weil es meines Achtens bei den ersten Versuchen nicht ohne geklappt hat.

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    3. TreeView1.Nodes(3).EnsureVisible()
    4. End Sub
    Bilder
    • vorher.png

      1,1 kB, 127×103, 94 mal angesehen
    • nachher.png

      1,2 kB, 127×103, 94 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo RFG,

    Das habe ich bemerkt. Ich beobachte aber auch, dass TreeNodes die sich außerhalb des sichtbaren Bereichs befinden und mit EnsureVisible() sichtbar gemacht werden, im unteren Bereich des TreeViews angezeigt werden.

    @VaporiZed
    wir haben gleichzeitig geschrieben, und ich hatte deine Antwort noch nicht auf dem Schirm.
    Ich habe dein Bsp. mit der Find Methode umgesetzt und nicht mit dem tatsächlichen Index des Nodes.

    Ich wollte dein Bsp. jetzt einmal mit dem Index umsetzen, aber irgendwie kapier ich das nicht, den Index herauszufinden. ich bekomme immer nur 0, 1, 2,3..., je nach Tiefe der Knotens ausgegeben.

    Ich versuche das mal umzusetzen und meld mich dann nochmal.

    Vorab Danke und viele Grüße,
    Michal

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

    Geht auch:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim tn = TreeView1.Nodes.Find(TreeView1.SelectedNode.Name, True)
    3. If tn.Count <> 1 Then Return
    4. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    5. TreeView2.Nodes(TreeView2.Nodes.Count - 1).EnsureVisible()
    6. TreeView1.SelectedNode = tn(0)
    7. tn(0).EnsureVisible()
    8. TreeView2.SelectedNode = TreeView2.Nodes(TreeView1.SelectedNode.Index)
    9. TreeView2.Nodes(TreeView1.SelectedNode.Index).EnsureVisible()
    10. End Sub

    Zumindest bei Stammknoten
    Bilder
    • vorher.png

      2,36 kB, 254×103, 88 mal angesehen
    • nachher.png

      2,58 kB, 254×103, 88 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Als Zwischenlösung könntest Du erstmal die jeweiligen Stammknoten nach oben setzen:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    3. TreeView2.Nodes(TreeView2.Nodes.Count - 1).EnsureVisible()
    4. Dim tn = GetRootNodeOf(TreeView1.SelectedNode)
    5. TreeView1.SelectedNode = tn
    6. tn.EnsureVisible()
    7. TreeView2.SelectedNode = TreeView2.Nodes(tn.Index)
    8. TreeView2.SelectedNode.EnsureVisible()
    9. End Sub
    10. Private Function GetRootNodeOf(Node As TreeNode) As TreeNode
    11. Dim SelectedNode = Node
    12. Do Until SelectedNode.Parent Is Nothing
    13. SelectedNode = SelectedNode.Parent
    14. Loop
    15. Return SelectedNode
    16. End Function

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    erst mal Danke für dein Engagement und deine Hilfe.

    Ich habe deine Zwischenlösung mal in meinem Projekt getestet.

    Wäre eine gute Sache :), aber ich habe in meinem TreeView nur einen Stammknoten. Somit ist Zwischenlösung für meine Datenlage leider nicht anwendbar, Mist :/
    Nur ein Stammknoten? Ok, es ist Deine Programmlogik. Aber auch kein Problem. Dann änder die GetRootNode-Methode einfach:

    VB.NET-Quellcode

    1. Private Function GetRootNodeOf(Node As TreeNode) As TreeNode
    2. Dim SelectedNode = Node
    3. Do Until SelectedNode.Parent.Parent Is Nothing 'hier hab ich es geändert
    4. SelectedNode = SelectedNode.Parent
    5. Loop
    6. Return SelectedNode
    7. End Function


    ##########
    @Michl
    Oder das Ganze mit Selektierung und OnTop-Setzung eines selektierten Unterknotens:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim IndexOrder = GetIndexOrderOf(TreeView1.SelectedNode)
    3. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    4. TreeView1.SelectedNode.EnsureVisible()
    5. TreeView2.SelectedNode = GetNodeFrom(TreeView2, IndexOrder.Reverse)
    6. TreeView2.Nodes(TreeView2.Nodes.Count - 1).EnsureVisible()
    7. TreeView2.SelectedNode.EnsureVisible()
    8. End Sub
    9. Private Function GetIndexOrderOf(Node As TreeNode) As IEnumerable(Of Integer)
    10. Dim SelectedNode = Node
    11. Dim IndexOrder As New List(Of Integer) From {SelectedNode.Index}
    12. Do Until SelectedNode.Parent Is Nothing
    13. SelectedNode = SelectedNode.Parent
    14. IndexOrder.Add(SelectedNode.Index)
    15. Loop
    16. Return IndexOrder
    17. End Function
    18. Private Function GetNodeFrom(TreeView As TreeView, ReversedIndexOrder As IEnumerable(Of Integer)) As TreeNode
    19. Dim SelectedNode = TreeView.Nodes(ReversedIndexOrder(0))
    20. For i = 1 To ReversedIndexOrder.Count - 1
    21. SelectedNode = SelectedNode.Nodes(ReversedIndexOrder(i))
    22. Next
    23. Return SelectedNode
    24. End Function

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    Hi VaporiZed,

    ich habe mal dein letztes Bsp. in eine neue Form (frmTreeViewTest) portiert und dabei versucht meine TreeView-Inhalte abzubilden.
    Sieht von der Sache her, Inhaltlich ganz gut aus. :)

    Auch mit deinem Beispiel werden die selektierten ChildNodes mit "EnsureVisible()" nur ganz unten in den TreeViews angezeigt.

    Könntest du schauen, ob du einen Grund dafür findest?

    Danke und viele Grüße,
    Michl


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Explicit On : Option Strict On
    2. Public Class frmTreeViewTest
    3. Private LastSelNode As TreeNode = Nothing ' Merker, welches Node im TreeView2 zuletzt aktiviert war
    4. Private Sub frmTreeViewTest_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. Dim NoOfMainNodes As Integer = 25
    6. Dim NoOfSubNodes As Integer = 5
    7. 'TreeView1 **************
    8. 'Creating the root node
    9. TreeView1.Nodes.Add("0", "Root")
    10. 'Creating main nodes
    11. For i = 1 To NoOfMainNodes
    12. TreeView1.Nodes.Item("0").Nodes.Add("E" & i.ToString("00"), "Main_" & i.ToString("00"))
    13. Next
    14. 'Creating sub nodes
    15. For SNode = 1 To NoOfMainNodes
    16. For i = 1 To NoOfSubNodes
    17. TreeView1.Nodes.Find(CStr("E" & SNode.ToString("00")), True)(0).Nodes.Add("E" & i.ToString("00"), "Ebene_" & SNode.ToString("00") & "." & i.ToString("00"))
    18. Next
    19. Next
    20. 'TreeView2 **************
    21. 'Creating the root node
    22. TreeView2.Nodes.Add("0", "Root")
    23. 'Creating main nodes
    24. For i = 1 To NoOfMainNodes
    25. TreeView2.Nodes.Item("0").Nodes.Add("E" & i.ToString("00"), "Eintrag_" & i.ToString("00"))
    26. Next
    27. 'Creating sub nodes
    28. For SNode = 1 To NoOfMainNodes
    29. For i = 1 To NoOfSubNodes
    30. TreeView2.Nodes.Find(CStr("E" & SNode.ToString("00")), True)(0).Nodes.Add("E" & i.ToString("00"), "Text_" & SNode.ToString("00") & "." & i.ToString("00"))
    31. Next
    32. Next
    33. TreeView1.ExpandAll()
    34. TreeView2.ExpandAll()
    35. Dim tn = TreeView1.Nodes.Find("0", True)
    36. tn(0).EnsureVisible() 'Root-Eintrag in TreeView1 selektieren
    37. End Sub
    38. #Region "BSP 'VaporiZed' Post_13"
    39. Private Function GetIndexOrderOf(Node As TreeNode) As IEnumerable(Of Integer)
    40. Dim SelectedNode = Node
    41. Dim IndexOrder As New List(Of Integer) From {SelectedNode.Index}
    42. Do Until SelectedNode.Parent Is Nothing
    43. SelectedNode = SelectedNode.Parent
    44. IndexOrder.Add(SelectedNode.Index)
    45. Loop
    46. Return IndexOrder
    47. End Function
    48. Private Function GetNodeFrom(TreeView As TreeView, ReversedIndexOrder As IEnumerable(Of Integer)) As TreeNode
    49. Dim SelectedNode = TreeView.Nodes(ReversedIndexOrder(0))
    50. For i = 1 To ReversedIndexOrder.Count - 1
    51. SelectedNode = SelectedNode.Nodes(ReversedIndexOrder(i))
    52. Next
    53. Return SelectedNode
    54. End Function
    55. Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
    56. Dim IndexOrder = GetIndexOrderOf(TreeView1.SelectedNode)
    57. TreeView1.Nodes(TreeView1.Nodes.Count - 1).EnsureVisible()
    58. TreeView1.SelectedNode.EnsureVisible()
    59. TreeView2.SelectedNode = GetNodeFrom(TreeView2, IndexOrder.Reverse)
    60. TreeView2.Nodes(TreeView2.Nodes.Count - 1).EnsureVisible()
    61. TreeView2.SelectedNode.EnsureVisible()
    62. End Sub
    63. #End Region
    64. Private Sub TreeView2_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView2.AfterSelect
    65. 'Set Font Bold at selected node
    66. With TreeView2
    67. If Not IsNothing(LastSelNode) Then 'Zuvor selektiertes Node auf "Regulär" einstellen
    68. LastSelNode.NodeFont = New Font(.Font, FontStyle.Regular)
    69. End If
    70. .SelectedNode.NodeFont = New Font(.Font, FontStyle.Bold) 'Aktuell selektiertes Node auf "Bold" einstellen
    71. .SelectedNode.Text = .SelectedNode.Text 'Sicherstellen, dass der Fett-Geschriebene Text nicht abgeschnitten wird
    72. LastSelNode = .SelectedNode 'Aktuell selektiertes Node als zuletzt gewähltes Node setzen
    73. End With
    74. End Sub
    75. End Class
    Der Code funktioniert so nicht direkt, weil Du nur einen Stammknoten hast und damit der Code in Zeile#67 und #70 nicht so greift wie gewünscht. Letztenendes müsstest Du alle Knoten aufklappen und den allerletzten selektieren.
    Zwischenzeitlich klappt es aber damit in TreeView1_AfterSelect:

    VB.NET-Quellcode

    1. Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
    2. Dim IndexOrder = GetIndexOrderOf(TreeView1.SelectedNode)
    3. TreeView1.Nodes(0).Nodes(TreeView1.Nodes(0).Nodes.Count - 1).EnsureVisible()
    4. TreeView1.SelectedNode.EnsureVisible()
    5. TreeView2.SelectedNode = GetNodeFrom(TreeView2, IndexOrder.Reverse)
    6. TreeView2.Nodes(0).Nodes(TreeView2.Nodes(0).Nodes.Count - 1).EnsureVisible()
    7. TreeView2.SelectedNode.EnsureVisible()
    8. End Sub
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.