none
Treeview mit Daten aus Access-Datenbank füllen RRS feed

  • Frage

  • Hallo,

    ich möchte meinem aktuellen Projekt ein weiteres Fenster mit einer TreeView-Control hinzufügen. Die Daten, die im TreeView angezeigt werden sollen, sind Bereiche, Kategorien innerhalb der Bereiche und Objekte innerhalb der Kategorien. Ich habe mir eine Instanz meines Datenbank-DataSets erstellt und über Adapter das DataSet gefüllt:

    Dim dsBereichKategorie As New planerDataSet
    Dim taBereich As New planerDataSetTableAdapters.tblbereichTableAdapter
    Dim taKategorie As New planerDataSetTableAdapters.tblkategorieTableAdapter
    Dim taObjekt As New planerDataSetTableAdapters.tblobjektTableAdapter
    
    taBereich.Fill(dsBereichKategorie.tblbereich)
    taKategorie.Fill(dsBereichKategorie.tblkategorie)
    taObjekt.Fill(dsBereichKategorie.tblobjekt)
    

    Jetzt wollte ich eigentlich mit Hilfe von LINQ to DataSet das Treeview füllen, aber da kommt zurzeit nur heiße Luft :-(. Habt Ihr eine Idee, wie es weiter geht? Tausend Dank im Voraus für Eure Hilfe!

    Gruß
    Marcus


    Der erste Tag, an dem ich nichts Neues lerne, wird der Tag sein, an dem sich der Deckel über mir schließt...
    Dienstag, 7. September 2010 11:29

Antworten

  • Hallo Marcus,

    unten das ganze (untypisiert) via LINQ To DataSet.
    Einige Ausdrücke lassen sich mit typisierten DataSets vereinfachen, siehe Abfragen von typisierten DataSets
    und sehen dann nicht mehr ganz so umständlich aus ;-)

    Ich habe exemplarisch über "aktiv" gefiltert.
    Denkbar wäre zwar, alles in einer (geschachtelten) Query zusammenzufassen,
    das ist aber nicht unbedingt verständlicher...

    Eine weitere Lektüre von Informationen zum Programmieren (LINQ to DataSet) ist zu empfehlen,
    so nicht bereits angelesen.

    Was die ImageList angeht: Solange Du nicht jedem Knoten ein anderes Bild zuweisen willst,
    reicht eine Zuordnung von Treeview.ImageIndex und TreeView. SelectedImageIndex.
    Dort in der MSDN findet sich ein Beispiel, wie man es auf Knotenebene hinunter festlegen kann.

    Das Formular besteht aus einem TreeView1 und einer TextBox1 -
    mit letzterer wird für das Auswählen eines Objekts gezeigt,
    wie man sich via JOIN alle Daten zusammenholen kann.

    Imports System.Linq
    
    Public Class TreeViewForm
    
      Private planerDataSet As DataSet
    
      Private Sub TreeViewForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Erstellen des DataSets (hier untypisiert)
        planerDataSet = CreateDataSet()
    
        ' typisiert wäre: dsBereichKategorie.tblbereich
        ' mehr http://msdn.microsoft.com/de-de/library/bb399351.aspx
        Dim bereichQuery = From b In planerDataSet.Tables("tblBereich").AsEnumerable() _
                  Let BereichId = b.Field(Of Integer)("bereichid") _
                  Where b.Field(Of Boolean)("aktiv") = True _
                  Order By BereichId _
                  Select BereichId, Bereich = b.Field(Of String)("Bereich")
    
        For Each bereichRow In bereichQuery
          Dim bereichid = bereichRow.BereichId  ' in lokale Variable speichern
    
          ' Abfrage Kategorien im Bereich
          Dim kategorieQuery = From k In planerDataSet.Tables("tblKategorie").AsEnumerable() _
            Let KategorieId = k.Field(Of Integer)("kategorieid") _
            Where k.Field(Of Integer)("bereichid") = bereichid _
               AndAlso k.Field(Of Boolean)("aktiv") = True
            Order By KategorieId _
            Select KategorieId, Kategorie = k.Field(Of String)("Kategorie")
    
          Dim bereichNode = Me.TreeView1.Nodes.Add(bereichRow.Bereich)
          For Each kategorieRow In kategorieQuery
            Dim kategorieid = kategorieRow.KategorieId
            ' Abfrage Objekt in Kategorie
            Dim objektQuery = From o In planerDataSet.Tables("tblobjekt").AsEnumerable() _
              Let ObjektId = o.Field(Of Integer)("objektid") _
              Let ObjektNummer = o.Field(Of String)("objektnr") _
              Where o.Field(Of Integer)("kategorieid") = kategorieid _
              Order By ObjektNummer _
              Select ObjektId, Bezeichnung = ObjektNummer & " " & o.Field(Of String)("objektbezeichnung")
    
            Dim kategorieNode = bereichNode.Nodes.Add(kategorieRow.Kategorie)
            For Each objektRow In objektQuery
              With kategorieNode.Nodes.Add(objektRow.Bezeichnung)
                .Tag = objektRow.ObjektId  ' Für späteres Nachschlagen
                ' für alternative Bilder
                ' .ImageIndex =
                ' .SelectedImageIndex = 
              End With
            Next
          Next
        Next
      End Sub
    
      Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect
        If e.Node IsNot Nothing Then
          Dim objektid = CInt(e.Node.Tag)
    
          ' Mehr als Illustration für einen Join 
          Dim objektQuery = From o In planerDataSet.Tables("tblobjekt").AsEnumerable() _
                   Join k In planerDataSet.Tables("tblkategorie").AsEnumerable() _
                    On o.Field(Of Integer)("kategorieid") Equals k.Field(Of Integer)("kategorieid") _
                   Join b In (planerDataSet.Tables("tblbereich").AsEnumerable()) _
                    On b.Field(Of Integer)("bereichid") Equals k.Field(Of Integer)("bereichid") _
                   Where o.Field(Of Integer)("objektid") = objektid
              Select Bezeichnung = b.Field(Of String)("bereich") & "-" & _
                k.Field(Of String)("kategorie") & "-" & _
                o.Field(Of String)("objektbezeichnung")
    
          Dim anzeigeText = objektQuery.SingleOrDefault()
          Me.TextBox1.Text = anzeigeText
        End If
      End Sub
    
    #Region "CreateDataSet"
      Private Shared Function CreateDataSet() As DataSet
        Dim dataSet As New DataSet("planerDataSet")
    
        ' tblBereich erstellen
        Dim bereichTable = dataSet.Tables.Add("tblBereich")
        bereichTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("bereichid", GetType(Integer)), _
           New DataColumn("bereich", GetType(String)), _
           New DataColumn("aktiv", GetType(Boolean))})
        ' PrimaryKey
        Dim bereichId = bereichTable.Columns("bereichid")
        bereichTable.PrimaryKey = New DataColumn() {bereichId}
    
    
        ' tblKategorie erstellen
        Dim kategorieTable = dataSet.Tables.Add("tblKategorie")
        kategorieTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("kategorieid", GetType(Integer)), _
           New DataColumn("kategorie", GetType(String)), _
           New DataColumn("bereichid", GetType(Integer)), _
           New DataColumn("aktiv", GetType(Boolean))})
        ' PrimaryKey
        Dim kategorieId = kategorieTable.Columns("kategorieId")
        kategorieTable.PrimaryKey = New DataColumn() {kategorieId}
        ' Relation 
        Dim kategorieBereichId = kategorieTable.Columns("bereichid")
        dataSet.Relations.Add("BereichKategorieRelation", bereichId, kategorieBereichId, True)
    
    
        ' tblObjekt erstellen (Spalten verkürzt)
        Dim objektTable = dataSet.Tables.Add("tblObjekt")
        objektTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("objektid", GetType(Integer)), _
           New DataColumn("objektnr", GetType(String)), _
           New DataColumn("objektbezeichnung", GetType(String)), _
           New DataColumn("kategorieid", GetType(Integer)), _
           New DataColumn("bereichid", GetType(Integer))})
        ' PrimaryKey
        Dim objektId = kategorieTable.Columns("objektid")
        objektTable.PrimaryKey = New DataColumn() {objektId}
    
        ' Relation (Ohne Bereich, denn das wäre doppelt gehoppelt ;-)
        Dim objektKategorieId = objektTable.Columns("kategorieid")
        dataSet.Relations.Add("KategorieObjektRelation", kategorieId, objektKategorieId, True)
    
        ' Beispieldaten erzeugen
        bereichTable.Rows.Add(1, "1. Bereich", True)
        bereichTable.Rows.Add(2, "2. Bereich", False)  ' nicht aktiv
        bereichTable.Rows.Add(3, "3. Bereich", True)
    
    
        kategorieTable.Rows.Add(10, "Kategorie 10", 1, True)
        kategorieTable.Rows.Add(11, "Kategorie 11", 1, False) ' nicht aktiv
        kategorieTable.Rows.Add(12, "Kategorie 12", 1, True)
    
        kategorieTable.Rows.Add(20, "Kategorie 20", 2, True)
        kategorieTable.Rows.Add(21, "Kategorie 21", 2, False)
    
        kategorieTable.Rows.Add(30, "Kategorie 30", 3, True)
        kategorieTable.Rows.Add(31, "Kategorie 31", 3, True)
        kategorieTable.Rows.Add(32, "Kategorie 32", 3, True)
    
    
        objektTable.Rows.Add(101, "Nr 101", "Objekt 101", 10, 1)
        objektTable.Rows.Add(102, "Nr 102", "Objekt 102", 10, 1)
        objektTable.Rows.Add(111, "Nr 111", "Objekt 111", 11, 1)
        objektTable.Rows.Add(121, "Nr 121", "Objekt 121", 12, 1)
    
        objektTable.Rows.Add(301, "Nr 301", "Objekt 301", 30, 1)
        objektTable.Rows.Add(311, "Nr 311", "Objekt 311", 31, 1)
        objektTable.Rows.Add(321, "Nr 311", "Objekt 321", 32, 1)
    
        Return dataSet
      End Function
    #End Region
    End Class
    

    Nachhaken, falls Unklarheiten bestehen.

    Gruß Elmar

    • Als Antwort markiert mjanz Donnerstag, 9. September 2010 13:31
    Dienstag, 7. September 2010 19:45

Alle Antworten

  • Hallo Marcus,

    wenn Du verraten würdest, was in den drei Tabellen (an Spalten) steckt
    und wie die Hierarchie aussehen soll, wäre es deutlich einfacher.

    Gruß Elmar

    Dienstag, 7. September 2010 16:05
  • Hallo Elmar,

    die drei Tabellen sehen so aus:

    tblbereich:
    bereichid (int)
    bereich (nvarchar)
    aktiv (bit)

    tblkategorie:
    kategorieid (int)
    kategorie (nvarchar)
    bereichid (int)
    aktiv (bit)

    tblobjekt:
    objektid (int)
    objektnummer (nvarchar)
    objektbezeichnung (nvarchar)
    objektbeschreibung (nvarchar)
    bereichid (int)
    kategorieid (int)
    angelegt (date)
    autor (nvarchar)

    Das typisierte DataSet heißt planerDataSet.

    Das Treeview-Steuerelement stelle ich mir so vor:

    Bereich (Anzahl der enthaltenden Kategorien)
    - Kategorie (Anzahl der enthaltenen Objekte)
    -- [Objektnummer] Objektbezeichnung

    Ich würde gerne mit einer ImageList arbeiten. Einen geschlossenen Ordner, wenn eine Knoten geschlossen ist und einen offenen Ordner, wenn der Knoten expandiert ist. Ich hoffe, Du kannst etwas damit anfangen...

    Gruß
    Marcus


    Der erste Tag, an dem ich nichts Neues lerne, wird der Tag sein, an dem sich der Deckel über mir schließt...
    Dienstag, 7. September 2010 16:52
  • Hallo Marcus,

    unten das ganze (untypisiert) via LINQ To DataSet.
    Einige Ausdrücke lassen sich mit typisierten DataSets vereinfachen, siehe Abfragen von typisierten DataSets
    und sehen dann nicht mehr ganz so umständlich aus ;-)

    Ich habe exemplarisch über "aktiv" gefiltert.
    Denkbar wäre zwar, alles in einer (geschachtelten) Query zusammenzufassen,
    das ist aber nicht unbedingt verständlicher...

    Eine weitere Lektüre von Informationen zum Programmieren (LINQ to DataSet) ist zu empfehlen,
    so nicht bereits angelesen.

    Was die ImageList angeht: Solange Du nicht jedem Knoten ein anderes Bild zuweisen willst,
    reicht eine Zuordnung von Treeview.ImageIndex und TreeView. SelectedImageIndex.
    Dort in der MSDN findet sich ein Beispiel, wie man es auf Knotenebene hinunter festlegen kann.

    Das Formular besteht aus einem TreeView1 und einer TextBox1 -
    mit letzterer wird für das Auswählen eines Objekts gezeigt,
    wie man sich via JOIN alle Daten zusammenholen kann.

    Imports System.Linq
    
    Public Class TreeViewForm
    
      Private planerDataSet As DataSet
    
      Private Sub TreeViewForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Erstellen des DataSets (hier untypisiert)
        planerDataSet = CreateDataSet()
    
        ' typisiert wäre: dsBereichKategorie.tblbereich
        ' mehr http://msdn.microsoft.com/de-de/library/bb399351.aspx
        Dim bereichQuery = From b In planerDataSet.Tables("tblBereich").AsEnumerable() _
                  Let BereichId = b.Field(Of Integer)("bereichid") _
                  Where b.Field(Of Boolean)("aktiv") = True _
                  Order By BereichId _
                  Select BereichId, Bereich = b.Field(Of String)("Bereich")
    
        For Each bereichRow In bereichQuery
          Dim bereichid = bereichRow.BereichId  ' in lokale Variable speichern
    
          ' Abfrage Kategorien im Bereich
          Dim kategorieQuery = From k In planerDataSet.Tables("tblKategorie").AsEnumerable() _
            Let KategorieId = k.Field(Of Integer)("kategorieid") _
            Where k.Field(Of Integer)("bereichid") = bereichid _
               AndAlso k.Field(Of Boolean)("aktiv") = True
            Order By KategorieId _
            Select KategorieId, Kategorie = k.Field(Of String)("Kategorie")
    
          Dim bereichNode = Me.TreeView1.Nodes.Add(bereichRow.Bereich)
          For Each kategorieRow In kategorieQuery
            Dim kategorieid = kategorieRow.KategorieId
            ' Abfrage Objekt in Kategorie
            Dim objektQuery = From o In planerDataSet.Tables("tblobjekt").AsEnumerable() _
              Let ObjektId = o.Field(Of Integer)("objektid") _
              Let ObjektNummer = o.Field(Of String)("objektnr") _
              Where o.Field(Of Integer)("kategorieid") = kategorieid _
              Order By ObjektNummer _
              Select ObjektId, Bezeichnung = ObjektNummer & " " & o.Field(Of String)("objektbezeichnung")
    
            Dim kategorieNode = bereichNode.Nodes.Add(kategorieRow.Kategorie)
            For Each objektRow In objektQuery
              With kategorieNode.Nodes.Add(objektRow.Bezeichnung)
                .Tag = objektRow.ObjektId  ' Für späteres Nachschlagen
                ' für alternative Bilder
                ' .ImageIndex =
                ' .SelectedImageIndex = 
              End With
            Next
          Next
        Next
      End Sub
    
      Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect
        If e.Node IsNot Nothing Then
          Dim objektid = CInt(e.Node.Tag)
    
          ' Mehr als Illustration für einen Join 
          Dim objektQuery = From o In planerDataSet.Tables("tblobjekt").AsEnumerable() _
                   Join k In planerDataSet.Tables("tblkategorie").AsEnumerable() _
                    On o.Field(Of Integer)("kategorieid") Equals k.Field(Of Integer)("kategorieid") _
                   Join b In (planerDataSet.Tables("tblbereich").AsEnumerable()) _
                    On b.Field(Of Integer)("bereichid") Equals k.Field(Of Integer)("bereichid") _
                   Where o.Field(Of Integer)("objektid") = objektid
              Select Bezeichnung = b.Field(Of String)("bereich") & "-" & _
                k.Field(Of String)("kategorie") & "-" & _
                o.Field(Of String)("objektbezeichnung")
    
          Dim anzeigeText = objektQuery.SingleOrDefault()
          Me.TextBox1.Text = anzeigeText
        End If
      End Sub
    
    #Region "CreateDataSet"
      Private Shared Function CreateDataSet() As DataSet
        Dim dataSet As New DataSet("planerDataSet")
    
        ' tblBereich erstellen
        Dim bereichTable = dataSet.Tables.Add("tblBereich")
        bereichTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("bereichid", GetType(Integer)), _
           New DataColumn("bereich", GetType(String)), _
           New DataColumn("aktiv", GetType(Boolean))})
        ' PrimaryKey
        Dim bereichId = bereichTable.Columns("bereichid")
        bereichTable.PrimaryKey = New DataColumn() {bereichId}
    
    
        ' tblKategorie erstellen
        Dim kategorieTable = dataSet.Tables.Add("tblKategorie")
        kategorieTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("kategorieid", GetType(Integer)), _
           New DataColumn("kategorie", GetType(String)), _
           New DataColumn("bereichid", GetType(Integer)), _
           New DataColumn("aktiv", GetType(Boolean))})
        ' PrimaryKey
        Dim kategorieId = kategorieTable.Columns("kategorieId")
        kategorieTable.PrimaryKey = New DataColumn() {kategorieId}
        ' Relation 
        Dim kategorieBereichId = kategorieTable.Columns("bereichid")
        dataSet.Relations.Add("BereichKategorieRelation", bereichId, kategorieBereichId, True)
    
    
        ' tblObjekt erstellen (Spalten verkürzt)
        Dim objektTable = dataSet.Tables.Add("tblObjekt")
        objektTable.Columns.AddRange(New DataColumn() { _
           New DataColumn("objektid", GetType(Integer)), _
           New DataColumn("objektnr", GetType(String)), _
           New DataColumn("objektbezeichnung", GetType(String)), _
           New DataColumn("kategorieid", GetType(Integer)), _
           New DataColumn("bereichid", GetType(Integer))})
        ' PrimaryKey
        Dim objektId = kategorieTable.Columns("objektid")
        objektTable.PrimaryKey = New DataColumn() {objektId}
    
        ' Relation (Ohne Bereich, denn das wäre doppelt gehoppelt ;-)
        Dim objektKategorieId = objektTable.Columns("kategorieid")
        dataSet.Relations.Add("KategorieObjektRelation", kategorieId, objektKategorieId, True)
    
        ' Beispieldaten erzeugen
        bereichTable.Rows.Add(1, "1. Bereich", True)
        bereichTable.Rows.Add(2, "2. Bereich", False)  ' nicht aktiv
        bereichTable.Rows.Add(3, "3. Bereich", True)
    
    
        kategorieTable.Rows.Add(10, "Kategorie 10", 1, True)
        kategorieTable.Rows.Add(11, "Kategorie 11", 1, False) ' nicht aktiv
        kategorieTable.Rows.Add(12, "Kategorie 12", 1, True)
    
        kategorieTable.Rows.Add(20, "Kategorie 20", 2, True)
        kategorieTable.Rows.Add(21, "Kategorie 21", 2, False)
    
        kategorieTable.Rows.Add(30, "Kategorie 30", 3, True)
        kategorieTable.Rows.Add(31, "Kategorie 31", 3, True)
        kategorieTable.Rows.Add(32, "Kategorie 32", 3, True)
    
    
        objektTable.Rows.Add(101, "Nr 101", "Objekt 101", 10, 1)
        objektTable.Rows.Add(102, "Nr 102", "Objekt 102", 10, 1)
        objektTable.Rows.Add(111, "Nr 111", "Objekt 111", 11, 1)
        objektTable.Rows.Add(121, "Nr 121", "Objekt 121", 12, 1)
    
        objektTable.Rows.Add(301, "Nr 301", "Objekt 301", 30, 1)
        objektTable.Rows.Add(311, "Nr 311", "Objekt 311", 31, 1)
        objektTable.Rows.Add(321, "Nr 311", "Objekt 321", 32, 1)
    
        Return dataSet
      End Function
    #End Region
    End Class
    

    Nachhaken, falls Unklarheiten bestehen.

    Gruß Elmar

    • Als Antwort markiert mjanz Donnerstag, 9. September 2010 13:31
    Dienstag, 7. September 2010 19:45
  • Hallo Elmar,

    also ich muss hier mal eine Lobeshymne singen. Nach der Lektüre Deiner Links und des Codes konnte ich genau das Nachstellen, was ich wollte. Ich habe zwar noch das ein oder andere selber zwischengefummelt, um noch ein paar Kleinigkeiten dazu zu bekommen, aber als ich verstanden hatte wie es ging, lief das problemlos. Tausend Dank nochmal!

    LG
    Marcus


    Der erste Tag, an dem ich nichts Neues lerne, wird der Tag sein, an dem sich der Deckel über mir schließt...
    Donnerstag, 9. September 2010 13:35