2010-02-05 22 views
1

Aloha, J'essaie de remplir une vue arborescente sur une application Windows avec des données hiérarchiques à partir d'une base de données SQL.Windows Forms VB.NET - Remplir TreeView avec des données hiérarchiques

La structure de la base de données est:

id_def id_parent description 
1  NULL  Multidificiência 
2  NULL  Síndrome 
3  NULL  Outros 
4  1  Surdez de Transmissão 
5  2  Surdez Neurossensorial Ligeira 
6  3  Surdez Neurossensorial Média 

les enregistrements avec la valeur NULL à id_parent, sont les principales catégories et celles qui ont leur id_parent, sont des sous catégories.

Quelqu'un peut-il aider avec le code pour remplir le TreeView? Je réussi à le faire avec une application ASP.NET, si elle aide, voici le code:

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
     PopulateRootLevel(); 
} 

private void PopulateRootLevel() 
{ 
    SqlConnection objConn = new SqlConnection("Data Source=1.1.1.1;Initial Catalog=DREER_EDUCANDOS2006;User ID=sre_web;Password=xxx"); 
    SqlCommand objCommand = new SqlCommand("select id_deficiencia,descricao,(select count(*) FROM NecessidadesEspeciais WHERE id_deficiencia_pai=sc.id_deficiencia) childnodecount FROM NecessidadesEspeciais sc where id_deficiencia_pai IS NULL", objConn); 
    SqlDataAdapter da = new SqlDataAdapter(objCommand); 
    DataTable dt = new DataTable(); 
    da.Fill(dt); 
    PopulateNodes(dt, TreeView1.Nodes); 
} 

private void PopulateSubLevel(int parentid, TreeNode parentNode) 
{ 
    SqlConnection objConn = new SqlConnection("Data Source=1.1.1.1;Initial Catalog=DREER_EDUCANDOS2006;User ID=sre_web;Password=xxx"); 
    SqlCommand objCommand = new SqlCommand("select id_deficiencia,descricao,(select count(*) FROM NecessidadesEspeciais WHERE id_deficiencia_pai=sc.id_deficiencia) childnodecount FROM NecessidadesEspeciais sc where [email protected]_deficiencia_pai", objConn); 
    objCommand.Parameters.Add("@id_deficiencia_pai", SqlDbType.Int).Value = parentid; 
    SqlDataAdapter da = new SqlDataAdapter(objCommand); 
    DataTable dt = new DataTable(); 
    da.Fill(dt); 
    PopulateNodes(dt, parentNode.ChildNodes); 
} 


protected void TreeView1_TreeNodePopulate(object sender, TreeNodeEventArgs e) 
{ 
    PopulateSubLevel(Int32.Parse(e.Node.Value), e.Node); 
} 

private void PopulateNodes(DataTable dt, TreeNodeCollection nodes) 
{ 
    foreach (DataRow dr in dt.Rows) 
    { 
     TreeNode tn = new TreeNode(); 
     tn.Text = dr["descricao"].ToString(); 
     tn.Value = dr["id_deficiencia"].ToString(); 
     nodes.Add(tn); 

     //If node has child nodes, then enable on-demand populating 
     tn.PopulateOnDemand = ((int)(dr["childnodecount"]) > 0); 
    } 
} 
+0

Notez exactement quel est votre problème. Est-ce quelque chose comme ça que vous recherchez (peupler une winviews treeview "à la demande", exemple C# si): http://stackoverflow.com/questions/1851729/treeview-child-node-populating-problem/1851789#1851789 –

+0

Si vous jetez un oeil ici: http://aspalliance.com/732_Display_Hierarchical_Data_with_TreeView_in_ASPNET_20 c'est exactement ce que je prétends, mais pour Windows forme. –

+0

@Rui: Je suis impressionné :) Brièvement vérifié l'article; il semble que ma réponse à cette autre question devrait faire l'affaire pour vous. Il convertit plutôt bien en VB.NET en utilisant ce convertisseur: http://www.developerfusion.com/tools/convert/csharp-to-vb/ La seule chose qui ne marche pas est le lambda multi-ligne dans le QueueUserWorkItem , mais je suppose que cela pourrait être extrait d'une méthode distincte pour résoudre le problème. –

Répondre

2

Prenez une table avec des données hiérarchiques en elle:

Id Name        ParentNodeId 
1 Top-level node 1     -1 
2 A first-level child     1 
3 Another top-level node    -1 
4 Another first-level child   1 
5 First-level child in another branch 3 
6 A second-level child     2 

J'ai retravaillé l'échantillon code à partir de another SO answer, pour utiliser le tableau ci-dessus pour remplir dynamiquement une vue arborescente (en supposant que la table réside dans une base de données SQL Server). L'exemple de code est un peu lenghty ...

using System.Windows.Forms; 
using System.Threading; 
using System.Collections.Generic; 
using System.Data.SqlClient; 
public class TreeViewSample : Form 
{ 
    private TreeView _treeView; 
    public TreeViewSample() 
    { 
     this._treeView = new System.Windows.Forms.TreeView(); 
     this._treeView.Location = new System.Drawing.Point(12, 12); 
     this._treeView.Size = new System.Drawing.Size(200, 400); 
     this._treeView.AfterExpand += 
      new TreeViewEventHandler(TreeView_AfterExpand); 
     this.ClientSize = new System.Drawing.Size(224, 424); 
     this.Controls.Add(this._treeView); 
     this.Text = "TreeView Lazy Load Sample"; 
     PopulateChildren(null); 
    } 

    void TreeView_AfterExpand(object sender, TreeViewEventArgs e) 
    { 
     if (e.Node.Nodes.Count == 1 && e.Node.Nodes[0].Tag == "dummy") 
     { 
      PopulateChildren(e.Node); 
     } 
    } 

    private void PopulateChildren(TreeNode parent) 
    { 
     // this node has not yet been populated, launch a thread 
     // to get the data 
     int? parentId = parent != null ? (parent.Tag as DataNode).Id : (int?)null; 
     ThreadPool.QueueUserWorkItem(state => 
     { 
      IEnumerable<DataNode> childItems = GetNodes(parentId); 
      // load the data into the tree view (on the UI thread) 
      _treeView.BeginInvoke((MethodInvoker)delegate 
      { 
       PopulateChildren(parent, childItems); 
      }); 
     }); 
    } 

    private void PopulateChildren(TreeNode parent, IEnumerable<DataNode> childItems) 
    { 
     TreeNodeCollection nodes = parent != null ? parent.Nodes : _treeView.Nodes; 
     TreeNode child; 
     TreeNode dummy; 
     TreeNode originalDummyItem = parent != null ? parent.Nodes[0] : null; 
     foreach (var item in childItems) 
     { 
      child = new TreeNode(item.Text); 
      child.Tag = item; 
      dummy = new TreeNode("Loading. Please wait..."); 
      dummy.Tag = "dummy"; 
      child.Nodes.Add(dummy); 
      nodes.Add(child); 
     } 
     if (originalDummyItem != null) 
     { 
      originalDummyItem.Remove(); 
     } 
    } 

    private IEnumerable<DataNode> GetNodes(int? parentId) 
    { 
     List<DataNode> result = new List<DataNode>(); 
     using (SqlConnection conn = new SqlConnection(@"[your connection string]")) 
     using (SqlCommand cmd = new SqlCommand("select * from Nodes where ParentNodeId = @parentNodeId", conn)) 
     { 
      cmd.Parameters.Add(new SqlParameter("@parentNodeId", System.Data.SqlDbType.Int)); 
      cmd.Parameters["@parentNodeId"].Value = parentId != null ? parentId : -1; 
      conn.Open(); 
      using (SqlDataReader reader = cmd.ExecuteReader()) 
      { 
       int nodeIdCol = reader.GetOrdinal("NodeId"); 
       int nameCol = reader.GetOrdinal("Name"); 
       int parentIdCl = reader.GetOrdinal("ParentNodeId"); 
       while (reader.Read()) 
       { 
        result.Add(new DataNode 
         { 
          Id = reader.GetInt32(nodeIdCol), 
          Text = reader.GetString(nameCol), 
          ParentId = reader.IsDBNull(parentIdCl) ? (int?)null : reader.GetInt32(parentIdCl) 
         }); 
       } 
      } 
     } 
     return result; 
    } 
} 

public class DataNode 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public int? ParentId { get; set; } 
} 

Les données de code peuvent probablement aller chercher fait un peu plus joli en utilisant LINQ to SQL, mais je voulais la même chose pour être aussi complet que possible, donc je décidé laisser cela dehors pour garder la quantité de code vers le bas ... (cela nécessiterait l'inclusion de certaines classes Linq-to-SQL générées).

+0

Merci beaucoup, c'était exactement ce dont j'avais besoin. Cela fonctionne à 100%. Encore une fois, je vous remercie de m'avoir accordé du temps pour le code. –

+0

Fredrik, j'ai juste une autre question: Les nœuds enfants sont toujours peuplés avec la balise 'TreeViewSample.DataNode' qui vient avec la création du noeud factice. Comment puis-je associer l'étiquette à l'identifiant? Je ne suis pas sûr Si je me suis fait clair, ajoutez simplement un bouton: MessageBox.Show (treeView1.SelectedNode.Text.ToString() + treeView1.SelectedNode.Tag.ToString()); –

+0

@Rui: le noeud factice n'a que la chaîne '" factice "' affectée à la propriété 'Tag'. Les nœuds "réels" ont le 'DataNode' qu'ils représentent dans la propriété' Tag'.Donc, vous pouvez lancer 'Tag' à' DataNode' et obtenir l'ID à partir de là: 'MessageBox.Show (treeView1.SelectedNode.Text + (treeView1.SelectedNode.Tag en tant que DataNode) .Id.ToString());' –