[Source] Nourrir un TreeView avec une base de données
Voilà, c'est ma première contribution, donc merci de votre indulgence si j'oublie des choses ou si je n'ai pas encore la bonne présentation.
Je vais tenter de vous faire un exposé clair de l'idée et de sa mise en oeuvre.
Donc l'idée c'est de nourrir un TreeView avec des informations venant d'une BDD au lieu d'un fichier XML. Donc il n'y a pas de XmlDataSource.
Sur al gpe vous posez juste un TreeView, tout seul avec un seul apramettre, voici le code minimal, ensuite vous agrémentez comme bon vous semble :
Code:
1 2
|
<asp:TreeView ID="TV" runat="server" EnableViewState="false"></asp:TreeView> |
Maintenant voyons la BDD : il faut que vous métiez en place un objet de BDD (vues, proc stock, fonction, table, ...) qui aura la structure suivante :
Identifiant, Libelle, Parent.
Ceci partant du principe que le Parent va être égal à un identifiant sur un autre enregistrement, donc même type de données. Respectez également l'ordre des champs.
Enfin, le CodeBehind, les explications sont dans le code en commentaire :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
'à partir du PageLoad il faut remplir le ou les premiers noueds du TreeView avec ce code qui peut trés bien être dans une Sub déportée
Dim dt As DataTable = dm.ExecuterRequeteSimple("SELECT Identifiant, Libelle FROM lobdjetBDD WHERE Parent is null ORDER BY Parent")
'le ORDER c'est à vous de voir, ça peut être un autre champ qui serait ajouter en bout de ligne.
'la clause WHERE sert à déterminer le ou les noeuds de plus haut niveau, j'ai mis du NULL, j'aurais pu mettre un autre identifiant, 0 par exemple.
'Le chargement dans une DataTable est ce que j'ai trouvé de plus simple car j'ai un FrameWork perso qui me renvoi une DataTable en deux lignes de code
For Each dr As DataRow In dt.Rows
Dim NewNode As New TreeNode(dr(1), dr(0))
'là, on emploi les index de champs, histoire que ce soit plus facile, donc l'ordre des champs....
NewNode.PopulateOnDemand = True
NewNode.Expanded = False
NewNode.SelectAction = TreeNodeSelectAction.None
'c'est trois lignes là sont là pour l'exemple, parce que mon besoin à l'origine est comme ça, mais c'est là qu'on bricole le noeud pour lui donner l'apprence et les fonctions que l'on souhaite. Un With est certainemnt sympa.
TV.Nodes.Add(NewNode)
Next
'ensuite on active le PopulateOnDemand du TreeView pour remplir à la suite à chaque fois qu'un noeud se présente.
Protected Sub TV_TreeNodePopulate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles TV.TreeNodePopulate
Dim dtn As DataTable = dm.ExecuterRequeteSimple("SELECT Identifiant, Libelle FROM lobdjetBDD WHERE Parent = " & e.Node.Value & "ORDER BY Parent")
'Donc, là on récupère le niveau où l'on est pour remplir la suite d'où le e.Node.Value
For Each dr As DataRow In dtn.Rows
Dim NewNode As New TreeNode(dr(1), dr(0))
NewNode.PopulateOnDemand = True
NewNode.Expanded = False
NewNode.SelectAction = TreeNodeSelectAction.None
e.Node.ChildNodes.Add(NewNode)
Next
'Et on recommence le même travail que précédement, sauf que l'ajout final n'est pas le même, on ajoute au noeud et pas au TreeView direct.
End Sub |
Voilà, j'espère que ça va aider certains. Pour améliorer on peut mettre au point un Fonction déportée pour travailler le Noeud à la place d'un With répété dans le deux procédures, il suffira de retourner un TreeNode.
Par contre prenez bien garde à la performance des requête. Tel qu'il est fait là, le serveur va chercher dans la base à chaque clique sur un "plus", mais surtout, la page ne donne pas l'impression de cherche, peut être un point à améliorer avec un petit truc qui bouge pour dire que ça charge.
Si vous avez des question, évitez les MP, ma boite se remplirai trop vite, mais je vous promets de passer ici à chauqe fois que j'aurais une alerte message pour y répondre.
treeview généré de façon récursive
Dommage que je ne vois cet article que maintenant parce que du coup je me suis décarcassé à générer mon treeview dynamiquement à la façon récursive.
Donc les évênements populate je n'y ai pas touché.
Tout d'abord voici la structure de la table dans ma base de données :
id étant clé primaire (int)
value (varchar)
idparent (int) --> cléf étrangère pointant sur l'id de cette même table
Cela donne par exemple :
+Informatique
---+Base de Données
---------SQL-Server
---------MySql
---+Languages
---------Asp.net
---------Php
---------+.net
------------VB.net
------------C#.net
(A savoir que Informatique a un idparent=0)
Afin de rendre le code qui va suivre plus compréhensible, je vais expliquer comment j'ai abordé le treeview et les treenodes. Pour simplifier au max, un treeview peut être composé de treenodes eux-mêmes composés de treenodes eux-mêmes composés de treenodes ect... Ainsi un treeview peut être composé de treenodes eux-mêmes composés de treenodes enfants qui peuvent avoir des treenodes enfants ect...
Code:
1 2 3 4 5 6 7 8 9 10
|
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack = False Then
'on charge le treeview
LoadTreeviewComp()
End If
End Sub |
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
'permet de charger le treeview trv_competences
Private Sub LoadTreeviewComp(Optional ByRef tnode As TreeNode = Nothing, Optional ByVal idparent As Integer = 0)
'on se connecte afin de récupérer les noeuds correspondants
Dim myConnection As SqlConnection
myConnection = New SqlConnection()
myConnection.ConnectionString = ConfigurationSettings.AppSettings("ConnectionString")
myConnection.Open()
Dim sql As String
sql = "SELECT id,value as val FROM COMPETENCE where idparent=" & idparent
sql &= " ORDER BY value"
'on charge les valeurs dans un dataset
Dim ds As New DataSet
Dim adapter As New SqlDataAdapter(sql, myConnection)
adapter.Fill(ds)
adapter.Dispose()
myConnection.Close()
Dim r As DataRow
For Each r In ds.Tables(0).Rows
Dim newnode As TreeNode
newnode = New TreeNode(r("value"), r("id"))
LoadTreeviewComp(newnode, r("id"))
If idparent = 0 Then
trv_competences.Nodes.Add(newnode)
Else
tnode.ChildNodes.Add(newnode)
End If
newnode = Nothing
Next
r = Nothing
ds.Dispose()
End Sub |
Ce qui m'a posé problème était de comprendre qu'il faille s'attaquer au dernier noeud (l'enfant de l'enfant de l'enfant de ...) afin de pouvoir le racrocher à son parent qui a aussi un parent.
J'ai rapidement cherché une amélioration parce qu'à chaque clic sur une ligne du treeview, la page est renvoyé sur le serveur afin d'effectuer l'évênement selectednode. Ceci ne servant pas à grand chose dans la procédure de saisie d'une nouvelle ligne dans le treeview (par exemple rajouter le delphi au .net). Dans l'idée,il suffirait de cliquer sur .net, qui donnerait en javascript le focus à un champ de saisie tout en inscrivant dans un champ caché l'id du noeud cliqué,puis d'ajouter ensuite un libellé et d'insérer avec un bouton. Malheureusement je ne sais pas comment programmer du javascript sur un tel contrôle alors si vous avez des idées, elles sont les bienvenues.