Sql Windows窗体VB.NET-使用分层数据填充TreeView

Sql Windows窗体VB.NET-使用分层数据填充TreeView,sql,vb.net,treeview,hierarchical-data,Sql,Vb.net,Treeview,Hierarchical Data,阿罗哈, 我正在尝试使用SQL db中的分层数据填充windows窗体应用程序上的树视图 数据库的结构为: 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

阿罗哈, 我正在尝试使用SQL db中的分层数据填充windows窗体应用程序上的树视图

数据库的结构为:

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
id_父级为空的记录是主类别,id_父级为空的记录是子类别

有人能帮助编写代码来填充树视图吗? 我设法用ASP.NET应用程序实现了这一点,如果有帮助,下面是代码:

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 id_deficiencia_pai=@id_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);
    }
}

取一个表,其中包含一些层次结构数据:

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
我重新编写了中的示例代码,以使用上表动态填充树视图(假设该表位于SQL server数据库中)。代码示例有点长

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; }
}
使用System.Windows.Forms;
使用系统线程;
使用System.Collections.Generic;
使用System.Data.SqlClient;
公共类TreeViewSample:表单
{
私人树景(private TreeView);
公共TreeViewSample()
{
这._treeView=new System.Windows.Forms.treeView();
此._treeView.Location=新系统.图纸.点(12,12);
此._treeView.Size=新系统图尺寸(200400);
这个._treeView.AfterExpand+=
新的TreeviewVenthandler(TreeView_AfterExpand);
this.ClientSize=新系统.Drawing.Size(224424);
this.Controls.Add(this.\u treeView);
this.Text=“TreeView Lazy Load Sample”;
PopulateChildren(空);
}
void TreeView_AfterExpand(对象发送方,treevieventargs e)
{
if(e.Node.Nodes.Count==1&&e.Node.Nodes[0]。标记==“dummy”)
{
普及儿童(e.Node);
}
}
私有无效PopulateChildren(TreeNode父级)
{
//此节点尚未填充,请启动一个线程
//获取数据
int?parentId=parent!=null?(parent.Tag作为DataNode)。Id:(int?)null;
ThreadPool.QueueUserWorkItem(状态=>
{
IEnumerable childItems=GetNodes(parentId);
//将数据加载到树视图中(在UI线程上)
_BeginInvoke((MethodInvoker)委托
{
PopulateChildren(父项、子项);
});
});
}
私有void PopulateChildren(TreeNode父项、IEnumerable子项)
{
TreeNodeCollection节点=父节点!=null?父节点:_treeView.nodes;
树状幼体;
树形假人;
TreeNode originalDummyItem=parent!=null?parent.Nodes[0]:null;
foreach(childItems中的变量项)
{
child=新树节点(item.Text);
Tag=item;
dummy=新树节点(“正在加载,请稍候…”);
dummy.Tag=“dummy”;
添加(虚拟);
添加(子节点);
}
if(originalDummyItem!=null)
{
originalDummyItem.Remove();
}
}
私有IEnumerable GetNodes(int?parentId)
{
列表结果=新列表();
使用(SqlConnection conn=newsqlconnection(@“[您的连接字符串]”))
使用(SqlCommand cmd=newsqlcommand(“从ParentNodeId=@ParentNodeId,conn)的节点中选择*)
{
Add(新的SqlParameter(“@parentNodeId”,System.Data.SqlDbType.Int));
cmd.Parameters[“@parentNodeId”].Value=parentId!=null?parentId:-1;
conn.Open();
使用(SqlDataReader=cmd.ExecuteReader())
{
int nodeIdCol=reader.GetOrdinal(“NodeId”);
int nameCol=reader.GetOrdinal(“名称”);
int parentIdCl=reader.GetOrdinal(“ParentNodeId”);
while(reader.Read())
{
添加(新的数据节点)
{
Id=reader.GetInt32(nodeIdCol),
Text=reader.GetString(nameCol),
ParentId=reader.IsDBNull(parentIdCl)?(int?)null:reader.GetInt32(parentIdCl)
});
}
}
}
返回结果;
}
}
公共类数据节点
{
公共int Id{get;set;}
公共字符串文本{get;set;}
public int?ParentId{get;set;}
}

通过使用Linq to SQL,数据获取代码可能会变得更漂亮一些,但我希望它尽可能完整,所以我决定省去它以减少代码量。。。(这需要包含一些生成的Linq到SQL类)。

请确切地注意您的问题所在。你是不是在寻找这样的东西(在winforms treeview“随需应变”中填充一个C#示例):Tack för ditt svar fredrik=)如果你看一下这里:这正是我假装的,但对于windows窗体。@Rui:我印象深刻:)简要地检查了这篇文章;看来我对另一个问题的回答应该对你有帮助。使用此转换器,它可以很好地转换为VB.NET:唯一不太有效的是QueueUserWorkItem中的多行lambda,但我想可以将其提取到一个单独的方法来解决问题。我的女朋友是瑞典人=)如果我能解决它,我会告诉你,谢谢你的帮助。cheers@Rui:无论如何,这与asp.net和c有关,与vb.net无关。谢谢你,这正是我所需要的。它100%有效。再次感谢您花时间为我编写代码。Fredrik,我还有一个问题:子节点总是使用创建虚拟节点时附带的标记“TreeViewSample.DataNode”填充。如何将标记与Id关联?我不确定我是否说清楚了,只需添加一个按钮:MessageBox.Show(treeView1.SelectedNode.Text.ToString()+treeView1.SelectedNode.Tag.ToString())@Rui:虚拟节点仅将字符串
“dummy”
分配给
标记
属性。“真实”节点具有它们在中表示的
DataNode