Refer this, where the relationship of Categories are converted to the tree structure. Note that this design only works for a single parent multiple children hierarchy. A multiple parent structure would be a complete different story.
The fact that differentiate TreeView from other collection views is that it expects a HierarchicalDataSource as its data source type. Therefore we will have to custom build the data retrieval and methods.
I'll use the naming convention prefixing "Category" for my classes as it suits my purpose.
We'll have to implement these 4 classes.
1. CategoryTreeNode.cs - Represents a single node in the tree hierarchy.
2. CategoryTree.cs - Represents a collection of nodes under a parent node.
3. CategoryTreeDataSourceView.cs - Builds the structure for the provided root node.
4. CategoryTreeDataSource.cs - Acts as the data source for the TreeView control.
CategoryTreeDataSource initializes with a populated root node using NodeLists and Nodes. We'll have to build this beforehand and then feed the root node to the data source. A recursive method like below can be used to populate the root node.
public static void PopulateCategoryTreeNodeWithHierarchy(CategoryTreeNode node)
{
if (node != null)
{
//Use your own data retrieval method.
IList<Category> categories = AssistantFactory.SummonAssistant<CategoryAssistant> ().SelectChildren(node.Category.Id);
foreach (Category category in categories)
{
CategoryTreeNode treeNode = new CategoryTreeNode(category);
treeNode.Parent = node;
node.ChildCategories.Add(treeNode);
}
if (node.ChildCategories != null && node.ChildCategories.Count > 0)
{
foreach (CategoryTreeNode childNode in node.ChildCategories)
{
PopulateCategoryTreeNodeWithHierarchy(childNode);
}
}
}
}
CategoryTreeDataSource inherits "HierarchicalDataSourceControl" and "IHierarchicalDataSource". Since it inherits the interface "IHierarchicalDataSource" you will have to override its required method "HierarchicalDataSourceView GetHierarchicalView(string viewPath)" which returns an instance of "CategoryTreeDataSourceView".
CategoryTreeDataSourceView inherits "HierarchicalDataSourceView" which holds and returns nodes of the tree hierarchy.
CategoryTreeNode inherits "IHierarchyData" which requires you to implement below methods and props,
bool HasChildren { get; }
object Item { get; }
string Path { get; }
string Type { get; }
IHierarchicalEnumerable GetChildren();
IHierarchyData GetParent();
Most methods and props are self explanatory. The most important prop of these is the "Path" which specifies the path of a node down the hierarchy and needs to be setup carefully.
CategoryTree holds a collection of CategoryTreeNodes in a list and returns a converted IHierarchicalEnumerable required by the data source.
This is just a high level reference for the implementation. I've added the classes below for a clearer reference. Also you can visit the MSDN reference here for a more technical overview.
Cheers!
public class CategoryTreeDataSource : HierarchicalDataSourceControl, IHierarchicalDataSource
{
public CategoryTreeDataSourceView DataSourceView { get; set; }
public CategoryTreeNode RootNode { get; set; }
public CategoryTreeDataSource(CategoryTreeNode root) : base()
{
RootNode = root;
}
protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
if (DataSourceView == null)
{
DataSourceView = new CategoryTreeDataSourceView(RootNode);
}
return DataSourceView;
}
protected override ControlCollection CreateControlCollection()
{
return new ControlCollection(this);
}
}
public class CategoryTreeDataSourceView : HierarchicalDataSourceView
{
public CategoryTreeNode RootNode { get; set; }
public string ViewPath { get; set; }
public CategoryTreeDataSourceView(string path)
{
ViewPath = path;
}
public CategoryTreeDataSourceView(CategoryTreeNode root)
{
RootNode = root;
}
public override IHierarchicalEnumerable Select()
{
CategoryTree children = new CategoryTree();
if (RootNode != null && RootNode.ChildCategories != null)
{
foreach (CategoryTreeNode child in RootNode.ChildCategories)
{
children.Add(child);
}
}
return children;
}
}
public class CategoryTree : List<CategoryTreeNode>, IHierarchicalEnumerable
{
public IList<CategoryTreeNode> Categories { get; set; }
public CategoryTree() : base()
{
Categories = new List<CategoryTreeNode>();
}
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
return enumeratedItem as CategoryTreeNode;
}
}
public class CategoryTreeNode : IHierarchyData
{
public Category Category { get; set; }
public IList<CategoryTreeNode> ChildCategories { get; set; }
public CategoryTreeNode Parent { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public CategoryTreeNode(Category category)
{
Category = category;
Name = category.Name;
CategoryId = category.Id;
ChildCategories = new List<CategoryTreeNode>();
}
public static CategoryTreeNode GetRootCategoryTreeNode()
{
CategoryTreeNode node = new CategoryTreeNode(AssistantFactory.SummonAssistant<CategoryAssistant>().SelectRoot());
return node;
}
public static void PopulateCategoryTreeNodeWithHierarchy(CategoryTreeNode node)
{
if (node != null)
{
IList<Category> categories = AssistantFactory.SummonAssistant<CategoryAssistant>().SelectChildren(node.Category.Id);
foreach (Category category in categories)
{
CategoryTreeNode treeNode = new CategoryTreeNode(category);
treeNode.Parent = node;
node.ChildCategories.Add(treeNode);
}
if (node.ChildCategories != null && node.ChildCategories.Count > 0)
{
foreach (CategoryTreeNode childNode in node.ChildCategories)
{
PopulateCategoryTreeNodeWithHierarchy(childNode);
}
}
}
}
public IHierarchicalEnumerable GetChildren()
{
CategoryTree children = new CategoryTree();
foreach (CategoryTreeNode child in ChildCategories)
{
children.Add(child);
}
return children;
}
public IHierarchyData GetParent()
{
CategoryTreeNode parent = new CategoryTreeNode(AssistantFactory.SummonAssistant<CategoryAssistant>().Select(Category.ParentCategoryId));
return parent;
}
public bool HasChildren
{
get
{
return (ChildCategories != null && ChildCategories.Count > 0);
}
}
public object Item
{
get
{
return this;
}
}
public string Type
{
get
{
return this.GetType().ToString();
}
}
public string Path
{
get
{
CategoryTreeNode node = this;
string valuePath = String.Empty;
while ((node = node.Parent) != null)
{
valuePath = String.Concat(node.Category.Id.ToString(), "/", valuePath);
}
return String.Concat(valuePath, this.Category.Id.ToString());
}
}
}
