65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 父/子(分层)关系树状视图用户控件开发

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (45投票s)

2010年11月5日

CPOL

6分钟阅读

viewsIcon

196006

downloadIcon

4933

自定义TreeView Web 用户控件,用于处理无限层级父子关系数据

引言

对于有 ASP.NET 经验的人来说,用户控件的开发非常简单。Treeview 是 ASP.NET 中已有的一个控件。它主要用于创建数据树。它可以用来根据父/子数据表构建无限深度的树状数据。

背景

在本演示中,我将展示如何在 ASP.NET 中创建一个树状视图用户控件,该控件可以通过设置一些属性,根据父/子关系数据表构建数据树。

入门

  1. 打开 SQL Server 2005。
  2. 设计一个名为 Department 的表,其结构如下:

ParentChildTreeView/DepartmentTable.JPG

图 1

在上面的表结构中,IsActive 是一个位字段,仅在您希望激活或禁用该记录时使用。默认情况下,在向此表中插入每条记录时,通过赋予值 1 来激活它。

Department 表中插入一些父级和相关的子级数据。您可以参考下图。

ParentChildTreeView/DepartmentData.JPG

图 2

让我们看看在本演示的 Department 表中,我们如何在 SQL 表中找到父记录下的子记录。这在您的实际情况中可能会有所不同。您还需要识别父记录。实际上,记录在这里指的是单个 Department。单个部门可能有子部门,在这种情况下,顶层的 Department 是父部门或记录,而其下方的分层直接子部门或记录就是子部门或记录。分层下方的部门或记录被称为其上方直接分层部门的子级。这就是父子关系(分层)。通过这种机制,在一个具有上述 department 表结构的表中,您可能会拥有无限数量的父子记录。这种关系是通过表中自连接在主键和每个记录(在本例中是每个 department)的父键之间维护的。

ParentChildTreeView/Parent-Child.JPG

图 3

您可以通过检查父 ID 列中的 null 来找到层次结构中的最顶层父级。对于我们的 department 表,可以通过以下 SQL 查询获得:

SELECT * FROM Department WHERE Departmentidparent IS NULL

查询的输出

ParentChildTreeView/ParentRecord.JPG

图 4

您可以通过以下 SQL 查询找到父记录的子记录:

SELECT * FROM Department WHERE Departmentidparent=1

结果是:

ParentChildTreeView/HR.JPG

图 5

我们将把上述 SQL 操作应用到我们的控件创建代码中,以构建父/子关系记录的树状视图。

在 Visual Studio 2010 中创建 ASP.NET 网站

  1. 创建一个网站
  2. 添加 **Web 用户控件**

添加以下代码来创建控件代码隐藏页中的一些属性,以便可以从使用此树状视图用户控件的网页中进行配置。这些属性用于:

  1. DataSource - 父/子关系数据的来源
  2. DisplayMember - 用于树叶节点
  3. ValueMember - 保存显示成员的键值
  4. ParentMember - 父成员是子数据的父数据
  5. KeyMember - 键成员是父/子关系数据的​​主键
#region Property

        public DataTable DataSource
        {
            get;
            set;
        }

        public String DisplayMember
        {
            get;
            set;
        }

        public String ValueMember
        {
            get;
            set;
        }

        public String ParentMember
        {
            get;
            set;
        }

        public String KeyMember
        {
            get;
            set;
        }
#endregion

在控件的代码隐藏页中添加方法。要将父/子关系数据填充到树状视图控件中,您需要编写递归方法,如下面的代码所示。GetChildNode 是一个递归方法,它会一直调用,直到数据源中存在父子关系,并且它以父 ID 作为参数。PopulateTree 是递归方法 GetChildNode 的起始点。实际上,PopulateTree 通过将父 ID 作为参数调用 GetChildNode 来启动递归。请记住,父 ID 是当前行的主键。

GetChildNode 方法构建一个节点集合(TreeNodeCollection),直到最后一个子节点,并将其返回给 PopulateTree,以便它可以绑定到 Tree View 控件。

它通过过滤已加载到其中的数据源来查找子级,并为父 ID 构建条件。

CommonLoad 是一个调用 PopulateTree 方法的方法。最终,由加载事件调用。

在 Web 用户控件的代码隐藏页中添加 PopulateTree 方法。首先,您需要检查数据源中是否存在父/子关系数据。

 private void PopulateTree(TreeView objTreeView)
 {
   if (DataSource != null)
   {
   }
 }

使用 foreach 循环从上到下遍历所有记录。

foreach (DataRow dataRow in DataSource.Rows)
{
}

现在检查数据源中的第一个父记录。因此,对于所有从上到下遍历的记录,第一个父级是其父成员值为 null 的记录。

if (dataRow[ParentMember] == DBNull.Value)
{
}

将第一个父级作为根节点添加到树状视图中。

TreeNode treeRoot = new TreeNode();
treeRoot.Text = dataRow[DisplayMember].ToString();
treeRoot.Value = dataRow[ValueMember].ToString();
treeRoot.ImageUrl = "~/Images/Folder.gif";
treeRoot.ExpandAll();
objTreeView.Nodes.Add(treeRoot);   

现在,让我们创建一个递归方法,并在递归方法 GetChildNode 完成后回到 PopulateTree。我们都知道递归是一种可以调用自身直到满足某个条件的方法。GetChildNode 也是一个类似的递归方法,但它接受一个参数,该参数是用于查找该父级下的子级的父成员,然后由 PopulateTree 方法传递。最终,GetChildNode 方法返回一个 TreeNodeCollection,它是所有父节点及其下相关子节点的集合。

private TreeNodeCollection GetChildNode(long parentid)
{
}

现在进入 GetChildNode 方法。创建一个本地变量 TreeNodeCollecton,以便您可以临时保存节点集合,最后将其返回。

TreeNodeCollection childtreenodes = new TreeNodeCollection();

根据参数(即父成员)查找子记录。为此,您需要过滤由网页中的 DataSource 属性设置的数据源。因此,您需要将 DataSource 属性转换为 DataView,以便可以使用 data view 的 filter 属性对其进行过滤。请注意,DataTable 没有 filter 属性。

DataView dataView1 = new DataView(DataSource);
String strFilter = "" + ParentMember + "=" + parentid.ToString() + "";
dataView1.RowFilter = strFilter;

成功过滤后,您将仅获得参数传递过来的父成员下的子级。现在需要将这些子节点添加到作为参数传入的父节点下。

TreeNode childNode = new TreeNode();
childNode.Text = dataRow[DisplayMember].ToString();
childNode.Value = dataRow[ValueMember].ToString();
childNode.ImageUrl = "~/Images/oInboxF.gif";
childNode.ExpandAll();

在添加每个子节点时,您需要通过以父 ID 作为参数递归调用 GetChildNode 方法来为其检查子节点。在这种情况下,子记录的主键就是父 ID。如果存在子节点,则将它们作为子节点添加到当前作为父节点的节点下。

foreach (TreeNode cnode in GetChildNode(Convert.ToInt64(dataRow[KeyMember])))
{
   childNode.ChildNodes.Add(cnode);
}

最后,将这些节点添加到 TreeNodeCollection 中。

 childtreenodes.Add(childNode);

最后,当遍历完成时,返回 TreeNodeCollection

return childtreenodes;

现在让我们回到 PopulateTree。您将获得所有节点的集合,并且需要将所有节点添加到树状视图中。到目前为止,请按照以下代码操作:

foreach (TreeNode childnode in GetChildNode(Convert.ToInt64(dataRow[KeyMember])))
{
    treeRoot.ChildNodes.Add(childnode);
}

全部集合

#region Method

private void CommonLoad()
{
  PopulateTree(treeView);
}

 private void PopulateTree(TreeView objTreeView)
 {
            if (DataSource != null)
            {
                foreach (DataRow dataRow in DataSource.Rows)
                {
                    if (dataRow[ParentMember] == DBNull.Value)
                    {
                        TreeNode treeRoot = new TreeNode();
                        treeRoot.Text = dataRow[DisplayMember].ToString();
                        treeRoot.Value = dataRow[ValueMember].ToString();
                        treeRoot.ImageUrl = "~/Images/Folder.gif";
                        treeRoot.ExpandAll();
                        objTreeView.Nodes.Add(treeRoot);                  

                        foreach (TreeNode childnode in GetChildNode
			(Convert.ToInt64(dataRow[KeyMember])))
                        {
                            treeRoot.ChildNodes.Add(childnode);
                        }
                    }
                }
            }
        }

        private TreeNodeCollection GetChildNode(long parentid)
        {
            TreeNodeCollection childtreenodes = new TreeNodeCollection();
            DataView dataView1 = new DataView(DataSource);
            String strFilter = "" + ParentMember + "=" + parentid.ToString() + "";
            dataView1.RowFilter = strFilter;

            if (dataView1.Count > 0)
            {
                foreach (DataRow dataRow in dataView1.ToTable().Rows)
                {
                    TreeNode childNode = new TreeNode();
                    childNode.Text = dataRow[DisplayMember].ToString();
                    childNode.Value = dataRow[ValueMember].ToString();
                    childNode.ImageUrl = "~/Images/oInboxF.gif";
                    childNode.ExpandAll();

                    foreach (TreeNode cnode in GetChildNode
			(Convert.ToInt64(dataRow[KeyMember])))
                    {
                        childNode.ChildNodes.Add(cnode);
                    }
                    childtreenodes.Add(childNode);
                }
            }
            return childtreenodes;
        }

        #endregion

在控件的代码隐藏页中添加以下事件。

  #region event

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

这样,父/子树状视图 Web 用户控件就创建好了。您可以通过设置一些属性在网站中按需使用它。

在网站项目中添加一个测试页面。并将该控件放置在测试页的 aspx 页面中。

<%@ Register  Src="~/Controls/ParentChildTreeView.ascx" TagName="VTSTreeView" 

TagPrefix="uc1"  %>
<body>
    <form id="form1"  runat="server">    

        <uc1:VTSTreeView id="VTSTreeView1"  runat="server"/>
    
    </form>
</body>

在测试页的代码隐藏页中添加以下代码。并配置您在此页面中放置的树状视图用户控件。
首先,您需要为基础 SQL 表创建数据源。在本例中是 Department 表。并为 VTSTreeView1 控件设置以下属性,例如:

  • VTSTreeView1.DataSource = dataSet.Tables[0] - 数据表作为数据源
  • VTSTreeView1.KeyMember =DepartmentId - 主键
  • VTSTreeView1.DisplayMember =Name - 树叶节点
  • VTSTreeView1.ValueMember = DepartmentId - 树叶节点的值
  • VTSTreeView1.ParentMember = DepartmentIdParent - 当前树叶节点的父 ID。
protected void Page_Load(object sender, EventArgs e)
{
   if (!Page.IsPostBack)
     CommonLoad();           
}

private void CommonLoad()
{
  using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings

["ApplicationServices"].ToString()))
   {
     SqlDataAdapter dataAdapter = new SqlDataAdapter
	("SELECT * FROM Department WHERE IsActive = 1 ", conn);
     DataSet dataSet = new DataSet();

     dataAdapter.Fill(dataSet);

     VTSTreeView1.DataSource = dataSet.Tables[0];
     VTSTreeView1.KeyMember = "DepartmentId";
     VTSTreeView1.DisplayMember = "Name";
     VTSTreeView1.ValueMember = "DepartmentId";
     VTSTreeView1.ParentMember = "DepartmentIdParent";
   }
}

运行应用程序。您将在浏览器中看到以下输出:

ParentChildTreeView/Output.JPG

图 6

结论

本演示将帮助您构建用于父/子(分层)关系数据的应用程序。

谢谢!

© . All rights reserved.