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

在自定义集合中实现 IHierarchy 支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (24投票s)

2007年7月18日

3分钟阅读

viewsIcon

164509

downloadIcon

1913

简要介绍如何使用 IHierarchy 系列接口装饰您的自定义集合以支持数据绑定。

Screenshot of the final output.

引言

这个快速教程将介绍 ASP.NET 2.0 提供的 IHierarchicalDataSource 的主要特性。 通过一个常见的强类型泛型列表和实体形式的数据集(一个商店的类别列表),并使用 IHierarchy 系列接口将它们绑定在一起,演示如何将任何自定义集合转换为有用的数据绑定工具。

背景

在 Web 上显示分层数据并非易事,如果您尝试将分层数据的自定义集合绑定到标准 ASP.NET TreeView 控件,您可能已经知道。无论数据的原始形状如何,循环并使用提供的 AddNode 方法进行绑定都非常痛苦。 您必须递归地查找父控件,确保数据已排序等等。总而言之,这是一个相当大的麻烦! 希望在查看以下内容后,您会发现使用此技术扩展自定义集合并消除所有嵌套数据麻烦会容易得多!

尽情享用!

使用代码

我已尝试尽可能无缝地打包此代码。 在 Visual Studio 2005 中打开它,您应该会看到一个文件路径 ASP.NET Web Site。 我为每个类对象都有一个文件(我想这就是我身上的“团队开发者”),并且在公共类中有一个 static 方法,用于将快速示例数据整齐地放入强类型泛型列表实现中。

查看 *Default.aspx* 页面应该会产生一个计算机商店产品类别 TreeView 的树视图,演示下面的代码。

继续表演...

首先,我们需要一个基本的实体和集合,我的看起来类似于这样

using System;
using System.Collections.Generic;

public class Category {

   private int _categoryId;
   private int _parentId;
   private string _name;
   
   public int CategoryId {
      get { return _categoryId; }
      set { _categoryId = value; }
   }
   
   public int ParentId {
      get { return _parentId; }
      set { _parentId = value; }
   }
   public string Name {
      get { return _name; }
      set { _name = value; }
   }

   public Category(int categoryId, int parentId, string name) {
      _categoryId = categoryId;
      _parentId = parentId;
      _name = name;
   }   
}

public class CategoryCollection : List<Category> {

   public CategoryCollection()
      : base() {
   }
}

在实体上实现 IHierarchyData

为了告诉 CLR 您的集合具有分层数据,它实际上必须是! 让我们通过添加 System.Web.UI 命名空间以及实现 IHierarchyData 接口及其必需的成员来实现这一点,如下所示

using System;
using System.Collections.Generic;
using System.Web.UI;

public class Category : IHierarchyData {
   ...

   #region IHierarchyData Members

   // Gets an enumeration object that represents all the child 
   // nodes of the current hierarchical node.
   public IHierarchicalEnumerable GetChildren() {

      // Call to the local cache for the data
      CategoryCollection children = new CategoryCollection();

      // Loop through your local data and find any children
      foreach (Category category in Common.GetCategoryData()) {
         if (category.ParentId == this.CategoryId) {
            children.Add(category);
         }
      }

      return children;
   }

   // Gets an IHierarchyData object that represents the parent node 
   // of the current hierarchical node.
   public IHierarchyData GetParent() {
      
      // Loop through your local data and report back with the parent
      foreach (Category category in Common.GetCategoryData()) {
         if (category.CategoryId == this.ParentId)
            return category;
      }

      return null;

   }

   public bool HasChildren {
      get {
         CategoryCollection children = GetChildren() as CategoryCollection;
         return children.Count > 0;
      }
   }

   // Gets the hierarchical data node that the object represents.
   public object Item {
      get { return this; }
   }

   // Gets the hierarchical path of the node.
   public string Path {
      get { return this.CategoryId.ToString(); }
   }

   public string Type {
      get { return this.GetType().ToString(); }
   }

   #endregion   
}

GetChildren()GetParent() 方法是真正发生魔力的地方。 这两个内部方法为层次结构的定义提供动力,并允许控件适当地链接它们。

在集合上实现 IHierarchicalEnumerable

为了使上面的代码立即生效,GetChildren() 方法依赖于我们返回 IHierarchicalEnumerable 的实现。

实现此接口很简单,只需编写一个方法 (GetHierarchyData()),该方法将确保集合中正确的对象类型,如下所示

public class CategoryCollection : List<Category>, IHierarchicalEnumerable {
   ...
   
   #region IHierarchicalEnumerable Members

   // Returns a hierarchical data item for the specified enumerated item.
   public IHierarchyData GetHierarchyData(object enumeratedItem) {
      return enumeratedItem as IHierarchyData;
   }

   #endregion
}

终于...一些输出!

要查看结果,只需创建一个新的 ASPX 页面并向其添加一个 ASP:TreeView 控件。 在代码隐藏中,以下代码片段会将新装饰的集合中的结果绑定到树视图,并在您定义的层次结构中组织它。

ASP.Net
----------------------------------------------------------
<asp:TreeView ID="uxTreeView" runat="server" />

Code Behind
----------------------------------------------------------
protected void Page_Load(object sender, EventArgs e) {

   if (!IsPostBack) {
            
      // Local cache of category data
      CategoryCollection collection = Common.GetRootCategories();

      // Bind the data source to your collection
      uxTreeView.DataSource = collection;
      uxTreeView.DataBind();
   }
}

现在您的集合和实体都对接口大肆宣传,您可以一次又一次地在层次结构显示控件上本地使用它们。

关注点

如果有人可以回答为什么这隐藏在 System.Web.UI 命名空间中的问题,我很乐意听取! 我无法想象这有“仅限 Web”的要求,但我尚未在 Windows 应用程序中尝试过它。

在代码下载中,我还包括了 IHierarchicalDataSourceHierarchicalDataSourceView 的实现,供那些喜欢使用 DataSource 控件在 ASPX 端以声明方式绑定数据的人使用。

历史

  • 2007 年 7 月 18 日,星期三 - 初始版本
© . All rights reserved.