Dieser Artikel konzentriert sich auf die Verwendung des TreeView-Steuerelements. Das TreeView-Steuerelement verfügt über umfangreiche Funktionen und kann in vielen Situationen verwendet werden. Zusammenfassung: Beschreibt, wie dem TreeView-Steuerelement Datenbindungsfunktionen hinzugefügt werden. Es handelt sich um eines aus einer Reihe von Beispielen für die Entwicklung von Microsoft Windows-Steuerelementen. Sie können diesen Artikel in Verbindung mit dem zugehörigen Übersichtsartikel lesen.
Einführung
Wenn möglich, sollten Sie mit Standardsteuerelementen beginnen, da die bereitgestellten Microsoft® Windows® Forms-Steuerelemente so viel Codierung und Tests umfassen, dass es eine Verschwendung wäre, sie aufzugeben und von vorne zu beginnen. Auf dieser Grundlage werde ich in diesem Beispiel ein vorhandenes Windows Forms-Steuerelement, TreeView, erben und es dann anpassen. Wenn Sie den Code für das TreeView- Steuerelement herunterladen, erhalten Sie außerdem zusätzliche Beispiele für die Steuerelemententwicklung sowie eine Beispielanwendung, die zeigt, wie Sie das erweiterte TreeView mit anderen datengebundenen Steuerelementen verwenden.
Entwerfen einer Datenbindungsbaumansicht
Für Windows-Entwickler ist das Hinzufügen von Datenbindungen zum TreeView- Steuerelement ein häufiges Problem. Da es jedoch einen großen Unterschied zwischen TreeView und anderen Steuerelementen (z. B. ListBox oder DataGrid ) gibt (d. h. TreeView zeigt hierarchische Daten an), ist das grundlegende Steuerelement diese Funktion noch nicht unterstützt (das heißt, wir müssen es noch verwenden). Bei einer gegebenen Datentabelle ist klar, wie diese Informationen in einer ListBox oder einem DataGrid angezeigt werden, aber die Verwendung der Ebenenstruktur einer TreeView zur Anzeige derselben Daten ist nicht so einfach. Persönlich habe ich beim Anzeigen von Daten mit TreeView viele verschiedene Methoden angewendet, aber es gibt eine Methode, die am häufigsten verwendet wird: das Gruppieren der Daten in der Tabelle nach bestimmten Feldern, wie in Abbildung 1 dargestellt.
Abbildung 1: Daten in TreeView anzeigen
In diesem Beispiel erstelle ich ein TreeView- Steuerelement, in dem ich einen flachen Datensatz (dargestellt in Abbildung 2) übergeben und problemlos die in Abbildung 1 gezeigten Ergebnisse erzeugen kann.
Abbildung 2: Flache Ergebnismenge mit allen Informationen, die zum Erstellen des in Abbildung 1 gezeigten Baums erforderlich sind
Bevor ich mit dem Codieren begann, habe ich mir einen Entwurf für das neue Steuerelement ausgedacht, der diesen speziellen Datensatz verarbeiten würde und hoffentlich auch in vielen anderen ähnlichen Situationen funktionieren würde. Fügen Sie eine Gruppensammlung hinzu, die groß genug ist, um eine Hierarchie mit den meisten flachen Daten zu erstellen, in der Sie ein Gruppierungsfeld, ein Anzeigefeld und ein Wertefeld für jede Hierarchieebene angeben (bestimmte oder alle Felder sollten gleich sein). Um die in Abbildung 2 gezeigten Daten in die in Abbildung 1 gezeigte TreeView umzuwandeln, erfordert mein neues Steuerelement, dass Sie zwei Gruppierungsebenen definieren, Publisher und Title, und pub_id als Gruppierungsfeld der Publisher-Gruppe und title_id als Gruppierungsfeld definieren der Gruppierungsgruppe. Zusätzlich zu den Gruppierungsfeldern müssen Sie auch Anzeige- und Wertefelder für jede Gruppe angeben, um den Text zu bestimmen, der auf dem entsprechenden Gruppenknoten angezeigt wird, und den Wert, der die spezifische Gruppe eindeutig identifiziert. Wenn Sie auf diese Art von Daten stoßen, verwenden Sie pub_name/pub_id und title/title_id als Anzeige-/Wertfelder für diese beiden Gruppen. Die Autoreninformationen werden zu den Blattknoten des Baums (den Knoten am Ende der Gruppierungshierarchie), und Sie müssen außerdem die Felder ID ( au_id ) und Anzeige ( au_lname ) für diese Knoten angeben.
Wenn Sie ein benutzerdefiniertes Steuerelement erstellen, können Sie die Effizienz des Steuerelements steigern, indem Sie festlegen, wie der Programmierer das Steuerelement verwenden wird, bevor er mit dem Codieren beginnt. In diesem Fall möchte ich, dass der Programmierer (angesichts der zuvor angezeigten Daten und des gewünschten Ergebnisses) in der Lage ist, die Gruppierung mit ein paar Codezeilen wie diesem durchzuführen:
Mit DbTreeControl .ValueMember = au_id .DisplayMember = au_lname .DataSource = myDataTable.DefaultView .AddGroup(Publisher, pub_id, pub_name, pub_id) .AddGroup(Titel, title_id, title, title_id) Ende mit |
Hinweis: Dies ist nicht die letzte Codezeile, die ich geschrieben habe, aber sie ist ähnlich. Während der Entwicklung des Steuerelements wurde mir klar, dass ich den Bildindex in der ImageList, die mit der TreeView verknüpft ist, jeder Gruppierungsebene zuordnen musste, also musste ich der AddGroup -Methode einen zusätzlichen Parameter hinzufügen.
Um den Baum tatsächlich zu erstellen, gehe ich die Daten durch und suche nach Änderungen an den Feldern (angegeben als Gruppierungswerte für jede Gruppierung), während ich bei Bedarf neue Gruppierungsknoten und einen Blattknoten für jedes Datenelement erstelle. Aufgrund der Gruppierungsknoten ist die Gesamtzahl der Knoten größer als die Anzahl der Elemente in der Datenquelle, es gibt jedoch genau einen Blattknoten für jedes Element in den zugrunde liegenden Daten.
Abbildung 3: Gruppenknoten und Blattknoten
Die Unterscheidung zwischen Blattknoten und Gruppenknoten (dargestellt in Abbildung 3) wird für den Rest dieses Artikels wichtig sein. Ich habe beschlossen, diese beiden Knotentypen unterschiedlich zu behandeln, benutzerdefinierte Knoten für jeden Knotentyp zu erstellen und je nach ausgewähltem Knotentyp unterschiedliche Ereignisse auszulösen.
Implementieren Sie die Datenbindung
Der erste Schritt beim Schreiben von Code für dieses Steuerelement besteht darin, das Projekt und die entsprechende Startklasse zu erstellen. In diesem Beispiel erstelle ich zunächst eine neue Windows-Steuerelementbibliothek, lösche dann die Standardklasse „UserControl“ und ersetze sie durch eine neue Klasse, die vom TreeView -Steuerelement erbt:
Öffentliche Klasse dbTreeControl
Erbt System.Windows.Forms.TreeView
Von diesem Punkt an werde ich ein Steuerelement entwerfen, das in einem Formular platziert werden kann und das Aussehen und die Funktionalität eines regulären TreeView hat. Der nächste Schritt besteht darin, mit dem Hinzufügen des Codes zu beginnen, der für die Handhabung der neuen Funktionalität erforderlich ist, die dem TreeView hinzugefügt wird, nämlich Datenbindung und Gruppierung von Daten.
DataSource-Eigenschaft hinzufügen
Die gesamte Funktionalität meines neuen Steuerelements ist wichtig, aber zwei Schlüsselprobleme beim Erstellen komplexer datengebundener Steuerelemente sind die Handhabung der DataSource -Eigenschaften und das Abrufen einzelner Elemente aus jedem Objekt der Datenquelle.
Erstellen Sie eine Attributroutine
Erstens muss jedes Steuerelement, das zur Implementierung komplexer Datenbindungen verwendet wird, eine DataSource- Eigenschaftsroutine implementieren und entsprechende Mitgliedsvariablen verwalten:
Private m_DataSource als Objekt _ Öffentliche Eigenschaft DataSource() als Objekt Erhalten Gibt m_DataSource zurück Beenden Sie Get Set(ByVal Value As Object) Wenn Wert nichts ist, dann cm = Nichts GroupingChanged() Anders Wenn nicht (TypeOf Value ist IList oder _ TypeOf Value ist IListSource) Dann ' ist für diesen Zweck keine gültige Datenquelle Neue System.Exception auslösen (ungültige Datenquelle) Anders Wenn TypeOf Value IListSource ist, dann Dimmen Sie myListSource als IListSource myListSource = CType(Value, IListSource) Wenn myListSource.ContainsListCollection = True, dann Neue System.Exception auslösen (ungültige Datenquelle) Anders „Ja, ja. Es handelt sich um eine gültige Datenquelle m_DataSource = Wert cm = CType(Me.BindingContext(Value), _ Währungsmanager) GroupingChanged() Ende wenn Anders m_DataSource = Wert cm = CType(Me.BindingContext(Value), _ Währungsmanager) GroupingChanged() Ende wenn Ende wenn Ende wenn Endsatz End-Eigenschaft |
Im Allgemeinen werden Objekte unterstützt, die als Datenquellen für komplexe Datenbindungen verwendet werden können. Diese Schnittstelle stellt die Daten als Sammlung von Objekten bereit und stellt mehrere nützliche Eigenschaften bereit, z. B. Count . Mein neues TreeView- Steuerelement erfordert ein IList -gestütztes Objekt in seiner Bindung, aber die Verwendung einer anderen Schnittstelle funktioniert gut, da es eine bequeme Möglichkeit bietet, ein IList- Objekt ( GetList ) abzurufen. Beim Festlegen der DataSource- Eigenschaft stelle ich zunächst fest, ob ein gültiges Objekt bereitgestellt wird, d. h. ein Objekt, das IList oder IListSource unterstützt. Was ich wirklich möchte, ist ein IList . Wenn das Objekt also nur IListSource unterstützt (z. B. DataTable ), verwende ich die GetList()- Methode dieser Schnittstelle, um das richtige Objekt abzurufen.
Einige Objekte, die IListSource implementieren (z. B. DataSet ), enthalten tatsächlich mehrere Listen, die durch die Eigenschaft „ContainsListCollection“ dargestellt werden. Wenn diese Eigenschaft True ist, gibt GetList ein IList- Objekt zurück, das eine Liste darstellt (mit mehreren Listen). In meinem Beispiel habe ich beschlossen, direkte Verbindungen zu IList -Objekten oder IListSource- Objekten zu unterstützen, die nur ein IList -Objekt enthalten, und Objekte zu ignorieren, die zusätzliche Arbeit zum Angeben einer Datenquelle erfordern, z. B. ein DataSet .
Hinweis: Wenn Sie solche Objekte ( DataSet oder ähnliches) unterstützen möchten, können Sie eine zusätzliche Eigenschaft (z. B. DataMember ) hinzufügen, um eine bestimmte Unterliste für die Bindung anzugeben.
Wenn die bereitgestellte Datenquelle gültig ist, ist das Endergebnis eine erstellte Instanz ( cm = Me.BindingContext(Value) ). Da diese Instanz für den Zugriff auf die zugrunde liegende Datenquelle, Objekteigenschaften und Standortinformationen verwendet wird, wird sie in lokalen Variablen gespeichert.
Fügen Sie Anzeige- und Wertelementeigenschaften hinzu
Eine DataSource ist der erste Schritt bei der Implementierung einer komplexen Datenbindung. Das Steuerelement muss jedoch wissen, welche spezifischen Felder oder Eigenschaften der Daten als Anzeige- und Wertelemente verwendet werden. Das Display- Element wird als Titel des Baumknotens verwendet, während auf das Value- Element über die Value- Eigenschaft des Knotens zugegriffen werden kann. Bei diesen Eigenschaften handelt es sich allesamt um Zeichenfolgen, die Feld- oder Eigenschaftsnamen darstellen, und können einfach zum Steuerelement hinzugefügt werden:
Privates m_ValueMember als String Privates m_DisplayMember als String _ Öffentliche Eigenschaft ValueMember() als String Erhalten Gibt m_ValueMember zurück Beenden Sie Get Set(ByVal Value As String) m_ValueMember = Wert Endsatz End-Eigenschaft _ Öffentliche Eigenschaft DisplayMember() als String Erhalten Gibt m_DisplayMember zurück Beenden Sie Get Set(ByVal Value As String) m_DisplayMember = Wert Endsatz End-Eigenschaft |
In dieser TreeView stellen diese Eigenschaften nur die Anzeige- und Wertelemente der Blattknoten dar, und die entsprechenden Informationen für jede Gruppierungsebene werden in der AddGroup -Methode angegeben.
Verwendung des CurrencyManager-Objekts
In der zuvor besprochenen Eigenschaft „ DataSource“ wird eine Instanz der Klasse „CurrencyManager“ erstellt und in einer Variablen auf Klassenebene gespeichert. Die über dieses Objekt aufgerufene Klasse „CurrencyManager“ ist ein wichtiger Bestandteil der Implementierung der Datenbindung, da sie über Eigenschaften, Methoden und Ereignisse verfügt, die die folgenden Funktionen ermöglichen:
Attribut-/Feldwert abrufen
Mit dem Objekt „CurrencyManager“ können Sie über die Methode „GetItemProperties“ Eigenschafts- oder Feldwerte, beispielsweise den Wert eines DisplayMember- oder ValueMember- Felds, aus einem einzelnen Element in einer Datenquelle abrufen. Verwenden Sie dann ein PropertyDescriptor- Objekt, um den Wert eines bestimmten Felds oder einer bestimmten Eigenschaft für ein bestimmtes Listenelement abzurufen. Der folgende Codeausschnitt zeigt, wie diese PropertyDescriptor- Objekte erstellt werden und wie die GetValue -Funktion verwendet wird, um den Eigenschaftswert eines Elements in der zugrunde liegenden Datenquelle abzurufen. Beachten Sie die List- Eigenschaft des CurrencyManager -Objekts: Sie bietet Zugriff auf die IList- Instanz, an die das Steuerelement gebunden ist:
Dimmen Sie myNewLeafNode als TreeLeafNode CurrObject als Objekt dimmen currObject = cm.List(currentListIndex) Wenn Me.DisplayMember <> AndAlso Me.ValueMember <> Dann 'Blattknoten hinzufügen? Dimmen Sie pdValue als System.ComponentModel.PropertyDescriptor Dimmen Sie pdDisplay als System.ComponentModel.PropertyDescriptor pdValue = cm.GetItemProperties()(Me.ValueMember) pdDisplay = cm.GetItemProperties()(Me.DisplayMember) myNewLeafNode = _ Neuer TreeLeafNode(CStr(pdDisplay.GetValue(currObject)), _ currObject, _ pdValue.GetValue(currObject), _ currentListIndex) |
GetValue ignoriert bei der Rückgabe eines Objekts den zugrunde liegenden Datentyp der Eigenschaft, sodass der Rückgabewert vor der Verwendung konvertiert werden muss.
Halten Sie datengebundene Steuerelemente synchron
Der CurrencyManager verfügt über eine weitere wichtige Funktion: Zusätzlich zum Zugriff auf gebundene Datenquellen und Elementeigenschaften ermöglicht er die Verwendung derselben DataSource zur Koordinierung der Datenbindung zwischen diesem Steuerelement und jedem anderen Steuerelement. Diese Unterstützung kann verwendet werden, um sicherzustellen, dass mehrere Steuerelemente, die gleichzeitig an dieselbe Datenquelle gebunden sind, auf demselben Element der Datenquelle bleiben. Für mein Steuerelement möchte ich sicherstellen, dass, wenn ein Element in der Baumstruktur ausgewählt wird, alle anderen Steuerelemente, die an dieselbe Datenquelle gebunden sind, auf dasselbe Element verweisen (den gleichen Datensatz, die gleiche Zeile oder sogar das gleiche Array, wenn Sie möchten). in Form einer Datenbank zu denken). Dazu überschreibe ich die OnAfterSelect -Methode im Basis -TreeView . In dieser Methode (die nach Auswahl des Baumknotens aufgerufen wird) setze ich die Position- Eigenschaft des CurrencyManager- Objekts auf den Index des aktuell ausgewählten Elements. Die mit dem TreeView -Steuerelement bereitgestellte Beispielanwendung veranschaulicht, wie Synchronisierungssteuerelemente das Erstellen datengebundener Benutzeroberflächen erleichtern. Um es einfacher zu machen, die Listenposition des aktuell ausgewählten Elements zu bestimmen, habe ich eine benutzerdefinierte TreeNode- Klasse ( TreeLeafNode oder TreeGroupNode ) verwendet und den Listenindex jedes Knotens in der von mir erstellten Position- Eigenschaft gespeichert:
Protected überschreibt Sub OnAfterSelect _ (ByVal e As System.Windows.Forms.TreeViewEventArgs) Dimmen Sie tln als TreeLeafNode Wenn TypeOf e.Node TreeGroupNode ist, dann tln = FindFirstLeafNode(e.Node) GroupArgs als neu dimmen groupTreeViewEventArgs(e) RaiseEvent AfterGroupSelect(groupArgs) ElseIf TypeOf e.Node ist dann TreeLeafNode dimmen Sie leafArgs als neues leafTreeViewEventArgs(e) RaiseEvent AfterLeafSelect(leafArgs) tln = CType(e.Node, TreeLeafNode) Ende wenn Wenn nicht, ist tln nichts, dann Wenn cm.Position <> tln.Position Dann cm.Position = tln.Position Ende wenn Ende wenn MyBase.OnAfterSelect(e) Sub beenden |
Im vorherigen Codeausschnitt ist Ihnen vielleicht eine Funktion namens FindFirstLeafNode aufgefallen, die ich hier kurz vorstellen möchte. In meinem TreeView entsprechen nur die Blattknoten (die letzten Knoten in der Hierarchie) Elementen in der DataSource , alle anderen Knoten werden nur zum Erstellen der Gruppierungsstruktur verwendet. Wenn ich ein leistungsstarkes datengebundenes Steuerelement erstellen möchte, muss ich immer ein Element auswählen, das der DataSource entspricht. Wenn ich also einen Gruppenknoten auswähle, finde ich den ersten Blattknoten unter der Gruppe, als ob dieser Knoten der ist aktuelle Auswahl. Sie können sich das Beispiel in Aktion ansehen, aber vorerst können Sie es auch gerne verwenden.
Private Funktion FindFirstLeafNode(ByVal currNode As TreeNode) _ Als TreeLeafNode Wenn TypeOf currNode TreeLeafNode ist, dann CType(currNode, TreeLeafNode) zurückgeben Anders Wenn currNode.Nodes.Count > 0, dann Rückgabe FindFirstLeafNode(currNode.Nodes(0)) Anders Nichts zurückgeben Ende wenn Ende wenn Funktion beenden |
Durch Festlegen der Position- Eigenschaft des CurrencyManager -Objekts werden andere Steuerelemente mit der aktuellen Auswahl synchronisiert. Wenn sich jedoch die Position anderer Steuerelemente ändert, generiert der CurrencyManager auch Ereignisse, sodass sich die Auswahl entsprechend ändert. Um eine gute datengebundene Komponente zu sein, sollte sich die Auswahl verschieben, wenn sich der Speicherort der Datenquelle ändert, und die Anzeige sollte aktualisiert werden, wenn die Daten für ein Element geändert werden. Von CurrencyManager werden drei Ereignisse ausgelöst: CurrentChanged , ItemChanged und PositionChanged . Das letzte Ereignis ist ziemlich einfach; einer der Zwecke des Währungsmanagers besteht darin, einen aktuellen Positionsindikator für die Datenquelle beizubehalten, sodass mehrere gebundene Steuerelemente alle denselben Datensatz oder dasselbe Listenelement anzeigen können. Dieses Ereignis wird immer dann ausgelöst, wenn sich die Position ändert. Die anderen beiden Ereignisse überschneiden sich manchmal und die Unterscheidung ist weniger klar. Im Folgenden wird beschrieben, wie diese Ereignisse in benutzerdefinierten Steuerelementen verwendet werden: PositionChanged ist ein relativ einfaches Ereignis und wird hier nicht beschrieben. Wenn Sie das aktuell ausgewählte Element in einem komplexen datengebundenen Steuerelement (z. B. Tree) anpassen möchten, verwenden Sie bitte The Ereignis. Das ItemChanged -Ereignis wird immer dann ausgelöst, wenn ein Element in der Datenquelle geändert wird, während CurrentChanged nur dann ausgelöst wird, wenn das aktuelle Element geändert wird.
In meinem TreeView habe ich festgestellt, dass jedes Mal, wenn ich ein neues Element auswählte, alle drei Ereignisse ausgelöst wurden. Deshalb habe ich beschlossen, das PositionChanged- Ereignis zu behandeln, indem ich das aktuell ausgewählte Element ändere, und mit den anderen beiden nichts zu tun. Es wird empfohlen, die Datenquelle in IBindingList umzuwandeln (wenn die Datenquelle IBindingList unterstützt) und stattdessen das ListChanged -Ereignis zu verwenden, aber ich habe diese Funktionalität nicht implementiert.
Private Sub cm_PositionChanged(ByVal sender As Object, _ ByVal e As System.EventArgs) Behandelt cm.PositionChanged Dimmen Sie tln als TreeLeafNode Wenn TypeOf Me.SelectedNode TreeLeafNode ist, dann tln = CType(Me.SelectedNode, TreeLeafNode) Anders tln = FindFirstLeafNode(Me.SelectedNode) Ende wenn Wenn tln.Position <> cm.Position Dann Me.SelectedNode = FindNodeByPosition(cm.Position) Ende wenn Sub beenden Private Überladungsfunktion FindNodeByPosition(ByVal index As Integer) _ Als TreeNode Rückgabe FindNodeByPosition(index, Me.Nodes) Funktion beenden Private Überladungsfunktion FindNodeByPosition(ByVal index As Integer, _ ByVal NodesToSearch As TreeNodeCollection) As TreeNode Dim i As Integer = 0 CurrNode als TreeNode dimmen Dimmen Sie tln als TreeLeafNode Do While i < NodesToSearch.Count currNode = NodesToSearch(i) ich += 1 Wenn TypeOf currNode TreeLeafNode ist, dann tln = CType(currNode, TreeLeafNode) Wenn tln.Position = index Dann Gibt currNode zurück Ende wenn Anders currNode = FindNodeByPosition(index, currNode.Nodes) Wenn nicht, ist currNode nichts, dann Gibt currNode zurück Ende wenn Ende wenn Schleife Nichts zurückgeben Funktion beenden |
Konvertieren Sie DataSource in einen Baum
Nachdem ich den Datenbindungscode geschrieben habe, kann ich fortfahren und den Code hinzufügen, um die Gruppierungsebenen zu verwalten, den Baum entsprechend zu erstellen und dann einige benutzerdefinierte Ereignisse, Methoden und Eigenschaften hinzuzufügen.
Managementgruppe
Um eine Sammlung von Gruppen zu konfigurieren, muss der Programmierer die Funktionen AddGroup , RemoveGroup und ClearGroups erstellen. Immer wenn die Gruppensammlung geändert wird, muss der Baum neu gezeichnet werden (um die neue Konfiguration widerzuspiegeln). Deshalb habe ich eine generische Prozedur namens GroupingChanged erstellt, die von verschiedenen Codes im Steuerelement aufgerufen werden kann, wenn sich die Umstände ändern und der Baum dazu gezwungen werden muss umgebaut werden:
Private TreeGroups als neue ArrayList() Public Sub RemoveGroup(ByVal-Gruppe als Gruppe) Wenn nicht, treeGroups.Contains(group) Then treeGroups.Remove(group) GroupingChanged() Ende wenn Sub beenden Öffentliche Überladungen Sub AddGroup(ByVal group As Group) Versuchen treeGroups.Add(group) GroupingChanged() Fangen Beenden Sie den Versuch Sub beenden Öffentliche Überladungen Sub AddGroup(ByVal name As String, _ ByVal groupBy As String, _ ByVal displayMember As String, _ ByVal valueMember As String, _ ByVal imageIndex As Integer, _ ByVal selectedImageIndex As Integer) Dim myNewGroup As New Group(name, groupBy, _ displayMember, valueMember, _ imageIndex, selectedImageIndex) Me.AddGroup(myNewGroup) Sub beenden Öffentliche Funktion GetGroups() As Group() Rückgabe CType(treeGroups.ToArray(GetType(Group)), Group()) Funktion beenden |
Spannbaum
Die eigentliche Rekonstruktion des Baums erfolgt durch zwei Prozesse: BuildTree und AddNodes . Da der Code für diese beiden Prozesse zu lang ist, listet dieser Artikel sie nicht alle auf, sondern versucht, ihr Verhalten zusammenzufassen (natürlich können Sie den vollständigen Code herunterladen, wenn Sie möchten). Wie bereits erwähnt, können Programmierer mit diesem Steuerelement interagieren, indem sie eine Reihe von Gruppen einrichten und diese Gruppen dann in BuildTree verwenden, um zu bestimmen, wie die Baumknoten eingerichtet werden. BuildTree löscht die aktuelle Knotensammlung und durchläuft dann die gesamte Datenquelle, um die Gruppierung der ersten Ebene (Herausgeber, der im Beispiel und Diagramm weiter oben in diesem Artikel erwähnt wurde) zu verarbeiten, und fügt einen Knoten für jeden unterschiedlichen Gruppierungswert hinzu (unter Verwendung der Daten im Beispiel). Fügen Sie für jeden Knoten einen Knoten mit einem pub_id -Wert hinzu und rufen Sie dann AddNodes auf, um alle Knoten unter der Gruppierung der ersten Ebene zu füllen. AddNodes ruft sich selbst rekursiv auf, um so viele Ebenen wie nötig zu verarbeiten und fügt nach Bedarf Gruppenknoten und Blattknoten hinzu. Verwenden Sie zwei benutzerdefinierte Klassen basierend auf TreeNode , um Gruppenknoten und Blattknoten zu unterscheiden und entsprechende Attribute für die beiden Knotentypen bereitzustellen.
Benutzerdefinierte TreeView-Ereignisse
Immer wenn ein Knoten ausgewählt wird, löst TreeView zwei Ereignisse aus: BeforeSelect und AfterSelect . Aber in meiner Steuerung wollte ich die Ereignisse von Gruppenknoten und Blattknoten unterscheiden, also habe ich meine eigenen Ereignisse BeforeGroupSelect/AfterGroupSelect und BeforeLeafSelect/AfterLeafSelect hinzugefügt. Zusätzlich zu den Basisereignissen habe ich auch eine benutzerdefinierte Ereignisparameterklasse ausgelöst:
Öffentliche Veranstaltung BeforeGroupSelect _ (ByVal sender As Object, ByVal e As groupTreeViewCancelEventArgs) Öffentliche Veranstaltung AfterGroupSelect _ (ByVal sender As Object, ByVal e As groupTreeViewEventArgs) Öffentliches EventBeforeLeafSelect _ (ByVal sender As Object, ByVal e As leafTreeViewCancelEventArgs) Öffentliche Veranstaltung AfterLeafSelect _ (ByVal sender As Object, ByVal e As leafTreeViewEventArgs) Geschützte Überschreibungen Sub OnBeforeSelect _ (ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Wenn TypeOf e.Node TreeGroupNode ist, dann GroupArgs als neu dimmen groupTreeViewCancelEventArgs(e) RaiseEvent BeforeGroupSelect(CObj(Me), groupArgs) ElseIf TypeOf e.Node ist dann TreeLeafNode LeafArgs als neu dimmen leafTreeViewCancelEventArgs(e) RaiseEvent BeforeLeafSelect(CObj(Me), leafArgs) Ende wenn MyBase.OnBeforeSelect(e) Sub beenden Protected überschreibt Sub OnAfterSelect _ (ByVal e As System.Windows.Forms.TreeViewEventArgs) Dimmen Sie tln als TreeLeafNode Wenn TypeOf e.Node TreeGroupNode ist, dann tln = FindFirstLeafNode(e.Node) GroupArgs als neu dimmen groupTreeViewEventArgs(e) RaiseEvent AfterGroupSelect(CObj(Me), groupArgs) ElseIf TypeOf e.Node ist dann TreeLeafNode dimmen Sie leafArgs als neues leafTreeViewEventArgs(e) RaiseEvent AfterLeafSelect(CObj(Me), leafArgs) tln = CType(e.Node, TreeLeafNode) Ende wenn Wenn nicht, ist tln nichts, dann Wenn cm.Position <> tln.Position Dann cm.Position = tln.Position Ende wenn Ende wenn MyBase.OnAfterSelect(e) Sub beenden |
Benutzerdefinierte Knotenklassen ( TreeLeafNode und TreeGroupNode ) und benutzerdefinierte Ereignisparameterklassen sind im herunterladbaren Code enthalten.
Beispielanwendung
Um den gesamten Code in diesem Beispielsteuerelement vollständig zu verstehen, sollten Sie verstehen, wie er in Ihrer Anwendung funktioniert. Die enthaltene Beispielanwendung verwendet die Access-Datenbank pubs.mdb und veranschaulicht, wie das Tree- Steuerelement mit anderen datengebundenen Steuerelementen zum Erstellen von Windows-Anwendungen verwendet werden kann. Zu den wichtigsten Funktionen, die in diesem Fall besonders hervorzuheben sind, gehören die Synchronisierung des Baums mit anderen gebundenen Steuerelementen und die automatische Auswahl von Baumknoten bei der Durchführung einer Suche in der Datenquelle.
Hinweis: Diese Beispielanwendung (mit dem Namen TheSample) ist im Download für diesen Artikel enthalten.
Abbildung 4: Demoanwendung für datengebundenes TreeView
Zusammenfassung
Das in diesem Artikel beschriebene datengebundene Tree -Steuerelement eignet sich nicht für jedes Projekt, das ein Tree- Steuerelement zum Anzeigen von Datenbankinformationen erfordert, führt jedoch eine Methode zum Anpassen des Steuerelements für persönliche Zwecke ein. Denken Sie daran, dass jedes komplexe datengebundene Steuerelement, das Sie erstellen möchten, größtenteils denselben Code wie das Tree-Steuerelement enthält. Sie können die zukünftige Steuerelemententwicklung vereinfachen, indem Sie den vorhandenen Code ändern.