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

  • VB.NET

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

    tragl schrieb:

    -mit {VARIABLE} können generell Variablen abgerufen werden? Oder "nur" in z.B. einem SQL-String? Ich kenn das nur mit & VARIABLE & - was dann auf den
    ersten Blick den Code unübersichtlich machen kann. mit den {} finde ich schöner.

    -das $-Zeichen vor dem Connect-String bewirkt genau was?

    Das ist ein neueres Feature von .Net, es heisst "String-Interpolation". Strings mit String-Interpolation sind gekennzeichnet durch vorangestelltes $. Wenn dem so ist, kann man innerhalb des Strings Variablen einfügen, in {}. Das verbessert die Leserlichkeit erheblich.
    Aber googel das: "String-Interpolation"



    Jo, ich hab auch ohne Buch gelernt - aber das hat gedauert.
    Effizient ist ein Buch lesen.
    Mindestens wenn du mit was in Berührung kommst, dieses im Buch nachlesen. Wirst feststellen, dann kann son langweiliges Buch auf einmal ganz spannend sein - weil einem so allerlei Zusammenhänge aufgehen.

    tragl schrieb:

    EDIT: Frage3: Schließt er denn die Verbindung wenn ein Fehler auftreten sollte?
    Ja - das gehört zum Verhalten des Using-Blocks.
    Wie gesagt: Nachlesen (am Besten im Löffelmann-Buch, aber Kühnel/Leibhard ist glaub ebensogut, und ist Online, während Löffi nur Pdf ist - jdfs. beides kostenlos)
    Das ist, wo ein Buch unschlagbar ist: Die Zusammenhänge aufzeigen zB. zwischen Interfaces im Allgemeinen, IDisposable-Interface im Besonderen, und den Eigenheiten eines Using-Blocks.
    Perfektes Beispiel für die Nützlichkeit eines Buches.
    Wie gesagt: Im Inet findste alle möglichen Tuts (es sind auch gute dabei, aber findest du die?), Aber diese Dinge sind zu wichtig, um sich da mit Halbwissen zufriedenzugeben.

    Ups - nein - die Verbindung schliesst nicht!
    Die würde schliessen, wenn die Connection selbst im UsingBlock instanziert würde, wird sie aber garnet - die kommt ja iwie aus der Luft geflogen.
    Also da muss Try-Finally her:

    VB.NET-Quellcode

    1. Public Sub DB_tree_lesen2(Datenbank As String, Tabelle As String, TV As TreeView)
    2. TV.Nodes.Clear()
    3. DB_connect(Datenbank)
    4. Dim noAdminSegment = If(My.Settings.AppMode = "User", " AND (nur_admin = False)", "")
    5. Dim sql = $"SELECT * FROM `{Tabelle}` WHERE (Aktiv = True){noAdminSegment} ORDER BY `Bezeichnung`"
    6. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing} ' die untergeordneten NodeCollections werden im Verlauf eingetragen/aktualisiert
    7. Dim types = "rpc"
    8. Using adp = New OleDbDataAdapter(sql, con), tbl = New DataTable
    9. con.Open()
    10. Try
    11. adp.Fill(tbl)
    12. For Each rw As DataRow In tbl.Rows
    13. Dim iNodes = types.IndexOf(rw("Typ").ToString)
    14. 'Node zufügen und gleich untergeordnete NodeCollection in nodeCollections eintragen/aktualisieren
    15. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Bezeichnung").ToString).Nodes
    16. Next
    17. Finally
    18. con.Close()
    19. End Try
    20. End Using
    21. End Sub
    Andererseits: Ist doch egal. Wenn da ein Fehler auftritt, kann das Proggi eh nicht weiter laufen, und wenn ein Programm beendet werden selbst hängende Connections beseitigt.
    Also TryFinally wieder wegmachen.
    (Aber vielleicht nachlesen - es besteht ein Zusammenhang mit Using!)

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

    perfekt.
    Ich hab' im Übrigen über deinen 2. Code noch die Keys mit eingefügt und kann mir somit die Prozeduren aufrufen :)
    ... sobald ich den Befehl dazu gefunden habe. Mit Application.Run geht's schonmal nicht (wieder ein Unterschied zur VBA) - aber wird schon.

    Danke
    Originaler (noch) Nichtskönner :D

    tragl schrieb:

    Keys mit eingefügt und kann mir somit die Prozeduren aufrufen
    tja, sowas ist eher nicht vorgesehen.
    Deine Keys sind Daten, und Daten sind kein Code.
    Aber hatte ich schon erwähnt: Es reicht doch, den Treeview zur Navigation auf die jeweilige Tabpage zu nutzen - auf der TabPage dann mögen Buttons sein, wo der User dann was tun kann.
    Aber wenn du unbedingt mit NodeDoubleClick Aktionen auslösen willst, musste wohl einen grossen Select Case schreiben, und je nach Key die gewünschte Methode aufrufen.
    Hatte ich auch schon gesagt: Dafür wäre Treenode.FullPath ebensogut geeignet wie deine Keys.
    Ich schau mir das mit der direkten Übergabe an die TabPages mal an - wird wohl die eleganteste Lösung sein.
    Allerdings wird das hier mit dem Namen schwierig, ich bekomme ein TabName ja nicht auf z.B. "1 = Logistik" benannt.
    Da finde ich den key sinnvoller, den kann ich ja so anpassen dass ich Tabs genauso benennen kann.

    Mit dem großen Case Select bin ich eher unzufrieden - wäre ggf. aber machbar, das hab' ich gerade für 2 Nodes probiert.

    Hast du noch einen Ansatz, wie ich die Root-Nodes in "Fett" dargestellt bekomme?
    Originaler (noch) Nichtskönner :D

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

    tragl schrieb:

    Hast du noch einen Ansatz, wie ich die Root-Nodes in "Fett" dargestellt bekomme?
    OwnerDrawing
    Da muss man das Treeview.DrawNode-Event verarbeiten und den NodeText selbst reinmalen.
    Zuvor muss man im Designer TV.DrawMode.OwnerDrawText einstellen.
    Und dann in die Graphics des EventArgs zeichnen. Das nervige daran ist - naja, mehrere Sachen
    • die Treenode-Breite ist für normalen Text berechnet - daher reicht der Platz nicht, und man muss tricksen (etwa durch Spaces an den Text anhängen)
    • Treenodes können normal, selectiert, focussiert sein - da muss man immer verschieden malen
    Ah - zur Textbreite hab ich grad eine Idee: Stell den Treeview-Font auf Fett, dann rechnet er die Treenode-Breite für fette Schrift.
    Und die nicht-fetten musste ja auch übermalen, die passen dan eh hinein.
    Ok, das ist mit dann zuviel Aufwand - der Thread hier bleibt ja im Netz, sodass ich da ggf. später mal drauf zurückgreife.
    Ansonsten ist meine Anfrage ja geklärt worden :)
    Originaler (noch) Nichtskönner :D

    Neu

    Ich nochmal. Ich hab' jetzt mal angefangen, das über XML zu steuern.
    Allerdings komme ich mit dem Auslesen einzelner Daten nicht klar (die
    SQL-Strings greifen ja nicht wirklich).
    Wie kann ich denn jetzt für den z.B. den Tree bestimmte Filterkriterien aus dem DS ziehen?

    hier der Code mit Filter (funzt nicht), ich weiß nicht wie er da auf "treeRow" kommt // die Sortierung nach "Nr" müsste hier auch noch irgendwie rein - also eigentlich 2 Filter, wollte aber erst mit einem
    testen.

    VB.NET-Quellcode

    1. Public Sub Tree_lesen(ByVal DS As DataSet, ByVal Tabelle As String, ByVal TV As TreeView)
    2. 'Code von ErfinderDesRades (vb-paradise.de) https://www.vb-paradise.de/index.php/Thread/130686-TreeView-aus-Datenbank-f%C3%BCllen-Child-Nodes-Problem/?postID=1129524#post1129665
    3. TV.Nodes.Clear()
    4. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    5. Dim modestring As String = Nothing
    6. ch_einstellungen_tree.DS_xml.Tables("tree").ReadXml(_XML_tree.FullName)
    7. If DS.Tables(Tabelle).Rows.Count < 1 Then
    8. Msg_error("keine Daten vorhanden!")
    9. End If
    10. '
    11. Dim dsfilter As DataRow()
    12. Select Case mode
    13. Case "Mitarbeiter"
    14. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Mitarbeiter = True")
    15. Case "TL"
    16. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("TL = True")
    17. Case "Erkrath"
    18. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Erkrath = True")
    19. Case "Admin"
    20. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Admin = True")
    21. End Select
    22. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing}
    23. Dim types = "rpc"
    24. For Each dsfilter In DS.Tables(Tabelle).Rows
    25. Dim iNodes = types.IndexOf(dsfilter("Typ").ToString)
    26. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(dsfilter("Key").ToString, dsfilter("Nr").ToString & " = " & dsfilter("Bezeichnung").ToString).Nodes
    27. Next
    28. 'For Each rw As DataRow In DS.Tables(Tabelle).Rows
    29. ' Dim iNodes = types.IndexOf(rw("Typ").ToString)
    30. ' nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Key").ToString, rw("Nr").ToString & " = " & rw("Bezeichnung").ToString).Nodes
    31. 'Next
    32. End Sub


    der Code ohne Filter funzt und lädt den Tree, allerdings komplett:

    VB.NET-Quellcode

    1. Public Sub Tree_lesen(ByVal DS As DataSet, ByVal Tabelle As String, ByVal TV As TreeView)
    2. 'Code von ErfinderDesRades (vb-paradise.de) https://www.vb-paradise.de/index.php/Thread/130686-TreeView-aus-Datenbank-f%C3%BCllen-Child-Nodes-Problem/?postID=1129524#post1129665
    3. TV.Nodes.Clear()
    4. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    5. Dim modestring As String = Nothing
    6. ch_einstellungen_tree.DS_xml.Tables("tree").ReadXml(_XML_tree.FullName)
    7. If DS.Tables(Tabelle).Rows.Count < 1 Then
    8. Msg_error("keine Daten vorhanden!")
    9. End If
    10. '
    11. Dim dsfilter As DataRow()
    12. Select Case mode
    13. Case "Mitarbeiter"
    14. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Mitarbeiter = True")
    15. Case "TL"
    16. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("TL = True")
    17. Case "Erkrath"
    18. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Erkrath = True")
    19. Case "Admin"
    20. dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select("Admin = True")
    21. End Select
    22. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing}
    23. Dim types = "rpc"
    24. 'For Each dsfilter In DS.Tables(Tabelle).Rows
    25. ' Dim iNodes = types.IndexOf(dsfilter("Typ").ToString)
    26. ' nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(dsfilter("Key").ToString, dsfilter("Nr").ToString & " = " & dsfilter("Bezeichnung").ToString).Nodes
    27. 'Next
    28. For Each rw As DataRow In DS.Tables(Tabelle).Rows
    29. Dim iNodes = types.IndexOf(rw("Typ").ToString)
    30. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Key").ToString, rw("Nr").ToString & " = " & rw("Bezeichnung").ToString).Nodes
    31. Next
    32. End Sub

    Bilder
    • unbenannt.png

      86,96 kB, 2.652×394, 17 mal angesehen
    • unbenannt2.png

      146,62 kB, 2.104×952, 17 mal angesehen
    Originaler (noch) Nichtskönner :D

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

    Neu

    Ah, sowas hatten wir doch gerstern erst:

    VB.NET-Quellcode

    1. Dim dsfilter As DataRow() 'dsfilter ist damit ein DataRow-Array!
    2. '...
    3. For Each dsfilter In DS.Tables(Tabelle).Rows

    Das For-Each kann zwar aus einer X-Collection ein X für dsfilter machen, aber da Du angegeben hast, das dsfilter ein Array ist, crasht das. Lass die Dim dsfilter-Zeile weg und schreib eines davon:
    For Each dsfilter As DataRow In DS.Tables(Tabelle).Rows
    oder
    For Each dsfilter In DS.Tables(Tabelle).Rows.Cast(of DataRow)
    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.

    Neu

    nochma String-Interpolation:

    VB.NET-Quellcode

    1. 'aus
    2. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Key").ToString, rw("Nr").ToString & " = " & rw("Bezeichnung").ToString).Nodes
    3. 'wird:
    4. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Key").ToString, $"{rw("Nr")} = {rw("Bezeichnung")}").Nodes
    kann sowohl " & " als auch .ToString entbehrlich machen



    ansonsten würde ich dringend empfehlen, mit typisiertem Dataset zu arbeiten. Das kommt am Ende typsicher und leserlicher raus:

    VB.NET-Quellcode

    1. 'rw As TreeRow
    2. Dim iNodes = types.IndexOf(rw.Typ)
    3. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw.Key, $"{rw.Nr} = {rw.Bezeichnung}").Nodes
    Also was zuvor mit 'StringSmells' für den Compiler unüberprüfbar zugegriffen wurde wird benannten Properties (rw.Typ, rw.Key, rw.Nr, rw.Bezeichnung) mit definiertem Datentyp (hier: alle As String, kann aber auch verschiedenste annere Datentypen annehmen.).
    gugge vier Views-Videos, wie man mit sowas arbeiten kann.
    Auch Filter werden auf diese Weise zum Kinderspiel.



    Hey! ich glaub ich kann sogar deinen untypisierten Code korrigieren und vereinfachen:

    VB.NET-Quellcode

    1. Public Sub Tree_lesen(ByVal DS As DataSet, ByVal Tabelle As String, ByVal TV As TreeView)
    2. TV.Nodes.Clear()
    3. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    4. Dim modestring As String = Nothing
    5. ch_einstellungen_tree.DS_xml.Tables("tree").ReadXml(_XML_tree.FullName)
    6. If DS.Tables(Tabelle).Rows.Count < 1 Then
    7. Msg_error("keine Daten vorhanden!")
    8. End If
    9. Dim dsfilter = ch_einstellungen_tree.DS_xml.Tables("tree").Select($"{mode} = True")
    10. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing}
    11. Dim types = "rpc"
    12. For Each rw In dsfilter
    13. Dim iNodes = types.IndexOf(rw("Typ").ToString)
    14. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw("Key").ToString, $"{rw("Nr")} = {rw("Bezeichnung")}").Nodes
    15. Next
    16. End Sub
    Das eigliche Problem ist/war glaub die falsche Benennung von dsFilter. Was soll das sein, ein dsFilter? ein Filter? ein Dataset? aber es ist doch ein Datarow-Array!
    Also nenne es auch so, dann versteht man den Code gleich besser, und versucht nicht, mit einem Datarow-Array durch eine DataTable zu iterieren (For Each dsfilter In DS.Tables(Tabelle).Rows)
    Also mit richtiger Benamung:

    VB.NET-Quellcode

    1. Dim filteredRows = ch_einstellungen_tree.DS_xml.Tables("tree").Select($"{mode} = True")
    2. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing}
    3. Dim types = "rpc"
    4. For Each rw In filteredRows
    5. '...
    6. Next
    sieht doch auf einmal ganz logisch aus, oder?

    Nomen est Omen! - beachte insbesondere die sehr treffende freie Übersetzung ;)

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

    Neu

    ok, das mit dem typisieren muss ich mir dann nochmal angucken. hab das dataset jetzt jedenfalls über den designer erstellt, über ein formular kann ich das füllen / bearbeiten / etc. - das klappt
    wunderbar und wird auch in eine xml gespeichert. Hier ist es ja auch relativ wurscht ob ich eine XML pro Tabelle nehme oder mehrere Tabellen in eine XML packe, richtig?
    Denn z.B. die TreeView einstellungen sollen in der Anwendung gespeichert werden - andere Tabellen wiederum sollen dann als XML auf einem Netzlaufwerk liegen.

    Ansonsten hab ich das mit dem Füllen des Trees in eine Art Funktion (Public Sub) gepackt, weil ich ggf. noch weitere Trees brauche - die ich damit ja auch füllen kann.
    Bin eigentlich davon ausgegangen, dass das DataSet damit typisiert ist aber dann hab ich das wohl nicht richtig verstanden - werde mich einlesen.

    Danke an euch!

    Edit: Die Sortierung nach einer Spalte wird nach meinem Wissen ja über ein DataView gesteuert. Müsste ich dann quasi erst das DataView erstellen mit der entsprechenden
    Sortierung und darauf dann den Select-Filter anwenden?


    Edit2: Hab's glaub ich - bzgl. der Typisierung

    VB.NET-Quellcode

    1. Public Sub Tree_lesen(ByVal DS As DataSet, ByVal Tabelle As String, ByVal TV As TreeView)
    2. 'Code von ErfinderDesRades (vb-paradise.de) https://www.vb-paradise.de/index.php/Thread/130686-TreeView-aus-Datenbank-f%C3%BCllen-Child-Nodes-Problem/?postID=1129524#post1129665
    3. TV.Nodes.Clear()
    4. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    5. Dim modestring As String = Nothing
    6. ch_einstellungen_tree.DS_xml.Tables("tree").ReadXml(_XML_tree.FullName)
    7. If DS.Tables(Tabelle).Rows.Count < 1 Then
    8. Msg_error("keine Daten vorhanden!")
    9. End If
    10. 'Dim rw As DS_xml.treeRow
    11. Dim filteredRows = ch_einstellungen_tree.DS_xml.Tables(Tabelle).Select($"{mode} = True")
    12. Dim nodeCollections = {TV.Nodes, Nothing, Nothing, Nothing}
    13. Dim types = "rpc"
    14. For Each rw As DS_xml.treeRow In filteredRows
    15. Dim iNodes = types.IndexOf(rw.Typ)
    16. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Nr} = {rw.Bezeichnung}").Nodes
    17. Next
    18. End Sub


    allerdings meckert er nun beim Hinzufügen der Nodes "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt" - Zeile 16 wird markiert
    und wenn ich den key mit einbinde und der leer ist meckert er auch weil da kein eintrag drinnen ist, trotz dass er als String übergeben werden soll. Nach meinem
    Verständnis können ja auch leere Strings übergeben werden

    VB.NET-Quellcode

    1. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add(rw.Key.ToString, $"{rw.Nr} = {rw.Bezeichnung}").Nodes


    Originaler (noch) Nichtskönner :D

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

    Neu

    nach welcher Spalte willst du denn sortieren?
    Achja - nach Bezeichnung.
    Nun - das geht schief, sobald ein ZahlenSegment mehrstellig wird.
    Weil Datenbanken und Dataview sortieren Texte lexicografisch das bedeutet: "3" ist grösser als "11".
    Deine "Bezeichnungen" stellen aber eine "TableOfContent" dar, und solch ist sehr speziell zu sortieren.



    Wenn du dein Dataset im Dataset-Designer erstellt hast, dann hast du bereits ein typisiertes Dataset.
    Dann solltest du es aber auch benutzen - also lernen, was dieses alle kann.
    Die Datentypen DataRow, DataView, Dataset dürfen in deinem Code nie mehr auftauchen - das ist immer der Beweis, dass du die typisierten Möglichkeiten eines typisierten Dataset in den Wind schlägst.
    Wenn du dein Dataset typisiert verwendest, kann man auch eine TableOfContent-Sortierung implementieren.



    Zum getrennten Abspeichern: Jaaa - ist möglich.
    Ob das eine gute Idee ist weiss ich nicht - ich arbeite grundsätzlich mit nur einer DatenDatei.

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

    Neu

    problem bleibt dasselbe: Wenn die Nummern String sind und nach Art eines InhaltsVerzeichnisses gebildet werden bedürfen sie einer speziellen Sortierung.

    Aber du kannst dein Projekt auch zippen und anhängen, inklusive BeispielDaten. Dann kann ich recht schnell aufzeigen, was mit typisierter Programmierung eines typisierten Datasets gemeint ist.
    Aber probier deinen Upload bitte selber aus - man soll ihn downloaden können, entpacken und im VisualStudio starten ohne erstmal 100 Fehlermeldungen beheben zu müssen.
    Ausserdem die Binaries daraus entfernen, also *.dll und *.exe.

    Neu

    Hab den Ordner "bin" weggelassen, Rest ist in der rar-Datei.
    Beim Starten meckert er, dass der "Key" leer ist - der Code dazu ist zu finden in mod_tree.vb, wenn man die Stelle mit dem Key weg lässt, dann meckert er
    dass der Objektverweis nicht auf eine Instanz festgelegt wurde (Zeile 17)

    Edit: hatte die XML vergessen. Die packst in irgendein Verzeichnis - welches beim Start der App abgefragt wird.
    Dateien
    • Logistik-Tool.rar

      (89,4 kB, 9 mal heruntergeladen, zuletzt: )
    • tree.xml

      (853 Byte, 17 mal heruntergeladen, zuletzt: )
    Originaler (noch) Nichtskönner :D

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

    Neu

    kann ich nicht öffnen.
    ---------------------------
    Fehler
    ---------------------------
    C:\Users\Account2\Downloads\Logistik-Tool.rar
    Das Archiv hat entweder ein unbekanntes Format oder ist beschädigt.
    ---------------------------
    OK
    ---------------------------
    Mach doch einfach ein zip: Kontextmenü-SendenAn-zip-komprimierten Ordner

    Neu

    hier im Zip-Format, sorry dass das andere nicht geklappt hat - kann ich mir nicht erklären
    Dateien
    • Logistik-Tool.zip

      (111,51 kB, 9 mal heruntergeladen, zuletzt: )
    Originaler (noch) Nichtskönner :D

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

    Neu

    So, erstmal habich Visual Studio - Empfohlene Einstellungen für dich erledigt.
    In Zukunft bitte selbst erledigen.
    Ist das wichtigste, was du aus diesem Thread lernen kannst, ist Vorraussetzung, dass du überhaupt programmieren lernen kannst.

    Dann die gruseligsten Benamungen korrigiert: Klassen beginnen mit GrossBuchstabe. Das gilt auch für Tabellen im TypDataset.
    und DateiNamen, Ordner etc. besser ohne Spaces, Minusse, Umlaute.

    Dein Fehler war datengetrieben - du hattest dem ausgewähltem User den RootNode garnet freigeschaltet.

    Dann habich die Typ-Spalte rausgeworfen - und wie gesagt: die Key-Spalte ist mir auch son Rauswurf-Kandidat.

    Ansonsten würde ich empfehlen, alle Module wegzumachen - brauch man nicht, und widerspricht dem Kapselungs-Prinzip.
    Ein FolderDialog gehört aufs Form - nicht in ein Modul Dialoge benutzen ist einfach
    Das Datenladen hab ich mir ein bischen vereinfacht - ich kanns nicht brauchen, in jedem Testlauf erstmal in einem FolderBrauser-Dialog herumklicksen zu müssen.
    Die Dataset-Logik habe ich in eine Partiale Dataset-Klasse verlegt - da gehört sie hin.

    naja - soweit erstmal.

    Ah - was ich noch dringend empfehle: SolutionExplorer - OpenSource Damit kannst du mit einem Klick deine Sources zippen, und hast damit ein Backup.
    Weil wenn du dir meine Vorschläge zu herzen nimmst, oder auch sonst noch am Datenmodell rumschraubst (insbesondere Umbenennungen, Spalten-Löschungen), kann passieren, dass man sich das ganze Projekt zerschiesst.
    Vor sowas also mal Backup klicksen, dann kann mans Projekt getrost verwüsten.



    Jo, was ich eiglich gecodet habe - TreeView füllen geht jetzt so:

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Public Sub FillTree(tv As TreeView)
    3. tv.Nodes.Clear()
    4. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    5. Dim filteredRows = Me.Tree.Select($"{mode} = True").Cast(Of TreeRow).ToList
    6. filteredRows.Sort(Function(x, y) String.CompareOrdinal(GetTocSortKey(x.Nr), GetTocSortKey(y.Nr)))
    7. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing}
    8. For Each rw In filteredRows
    9. Dim iNodes = rw.Nr.Split("."c).Length - 1
    10. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Nr} = {rw.Bezeichnung}").Nodes
    11. Next
    12. tv.ExpandAll()
    13. End Sub
    14. Private Shared Function GetTocSortKey(tocEntry As String) As String
    15. ' Datenbeispiel: "2.11.3 Blabla"
    16. 'parst die enthaltenen Zahlen nach Integer, konvertiert diese nach Char, und fügt die Chars zum Sortkey-String zusammen
    17. 'der Sortkey ist als Text nicht lesbar, aber String.CompareOrdinal() sortiert ihn auf TableOfContent-korrekte Weise.
    18. Dim spaceIndex = tocEntry.IndexOf(" "c)
    19. Dim splitteds = If(spaceIndex < 0, tocEntry, tocEntry.Substring(0, spaceIndex)).Split("."c)
    20. Dim numbs = splitteds.Select(AddressOf Integer.Parse)
    21. Return New String(numbs.Select(AddressOf Convert.ToChar).ToArray())
    22. End Function
    23. End Class
    Dassis jetzt objektorientiert, nämlich das Dataset füllt seine Tree-Tabelle in den Treeview ein (der ihr übergeben wird).
    bei Fragen fragen
    Dateien

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

    Neu

    Hey, vielen Dank dafür schonmal!

    ErfinderDesRades schrieb:

    So, erstmal habich Visual Studio - Empfohlene Einstellungen für dich erledigt.


    Da muss ich mich entschuldigen - ich hatte das Projekt einmal "frisch" aufgesetzt und dabei natürlich vergessen die Deppen-Einstellungen zu entfernen - sorry
    Ansonsten arbeite ich mich jetzt erstmal dadurch - das mit dem SolutionExplorer werd' ich mir definitiv anschauen.

    Das mit den Benennungen hab' ich mir schon fast gedacht. Es wird ja sicherlich auch eine Art "knigge" für Programmiersprachen geben - damit wollte ich mich aber erstmal
    nicht "rumärgern" - ich finde mich ja zurecht :) Aber ist natürlich sinnvoll wenn z.B. andere Leute mal da ran müssen.

    EDIT: "schadet" es denn wenn ich viele Module hab? Das nutz ich aktuell damit ich schneller meinen Code wiederfind.
    Originaler (noch) Nichtskönner :D

    Neu

    tragl schrieb:

    "schadet" es denn wenn ich viele Module hab? Das nutz ich aktuell damit ich schneller meinen Code wiederfind.
    Die Intention ist genau richtig - es zeigt sich darin dein Bedürfnis nach Architektur.
    Nur die Sprache vb.net bietet bereits ein ausgezeichnetes Instrumentarium, Architektur zu entwickeln: Namespaces, Klassen, Vererbung.
    Module sind ein VB6-Relikt und haben in diesem System keinen Platz.
    Man sieht es an der Intellisense, dass was in einem Modul angelegt ist, global und ohne Prefix überall verfügbar ist - dem Kapselungs-Prinzip also komplett in den A... getreten.
    Nee - lerne die Sprache, und lerne auch sinnvolle objektorientierte Architektur.

    Neu

    Update
    Ich hab der DataTable jetzt einen eigene SortKey-Spalte spendiert, damit auch die Bindingsource die Tabelle richtig sortieren kann - sodass sich das auch im DGV richtig darstellt. Das vereinfacht nebenbei auch die Tv-Befüllung nochmal.
    Die TreeDataTable aktualisiert die SortKeys automatisch, wenn eine Nr-Spalte geändert wird.

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Public Sub FillTree(tv As TreeView)
    3. tv.Nodes.Clear()
    4. Dim mode As String = My.Settings.Mitarbeiter_Funktion
    5. Dim filteredSorted = Tree.Select($"{mode} = True").Cast(Of TreeRow).OrderBy(Function(rw) rw.SortKey).ToList
    6. Dim nodeCollections = {tv.Nodes, Nothing, Nothing, Nothing}
    7. For Each rw In filteredSorted
    8. Dim iNodes = rw.Nr.Split("."c).Length - 1
    9. nodeCollections(iNodes + 1) = nodeCollections(iNodes).Add($"{rw.Nr} = {rw.Bezeichnung}").Nodes
    10. Next
    11. tv.ExpandAll()
    12. End Sub
    13. ''' <summary>erzeugt aus einem hierarchischen InhaltsVerzeichnis-Eintrag (TableOfContent - TOC) einen sich lexikografisch korrekt einordnenden SortKey.
    14. ''' Beispiel: "2.11.3 Blabla" konvertiert zu " 2 B 3" (verkettete 2-stellig-rechtsbündige Hex-Darstellung der Segmente)
    15. ''' MaxValue eines tocEntry-Segments ist folglich die grösste 2-stellige hex-darstellung: FF, in decimal: 255</summary>
    16. Private Shared Function GetTocSortKey(tocEntry As String) As String
    17. Dim spaceIndex = tocEntry.IndexOf(" "c)
    18. Select Case spaceIndex
    19. Case 0 : Throw New ArgumentException("mustn't start with ' '", NameOf(tocEntry))
    20. Case > 0 : tocEntry = tocEntry.Substring(0, spaceIndex)
    21. End Select
    22. Dim numbs = tocEntry.Split("."c).Select(AddressOf Integer.Parse).ToArray
    23. If numbs.Any(Function(n) n > Byte.MaxValue) Then Throw New ArgumentException("segments maximum is '255'", NameOf(tocEntry))
    24. Return String.Concat(numbs.Select(Function(n) $"{n,2:X}")) ' 2-stellig rechtsbündige Hex-Darstellung
    25. End Function
    26. Partial Class TreeDataTable
    27. Private Sub TreeDataTable_ColumnChanged(sender As Object, e As DataColumnChangeEventArgs) Handles Me.ColumnChanged
    28. If e.Column IsNot NrColumn Then Return
    29. Dim rw = DirectCast(e.Row, TreeRow)
    30. rw.SortKey = GetTocSortKey(rw.Nr)
    31. End Sub
    32. End Class 'TreeDataTable
    33. End Class 'dtsLogistik


    Ausserdem die Id-Spalte aus dem DGV verborgen.
    Dateien