Csharp: TreeNode
c# - How can I draw iterating ul-li List pattern? - Stack Overflow
https://pastehtml.com/view/dd9ttlh4x.html
what is the best approach to implement Tree View?<ul> <li>Level 1 a - Pastebin.com
How To Create Multi Level Menu Dynamically Using C# in ASP.NET - CodeProject
An ASP.NET AJAX TreeView control with templates - CodeProject
Auto-TOC Generation and Header Numbering - Revision - CodeProject
https://www.c-sharpcorner.com/article/create-jstree-simply/
https://gijgo.com/tree/demos/bootstrap-treeview
https://www.codeproject.com/articles/42861/amenu-a-simple-net-vertical-menu
https://www.cnblogs.com/Mryjp/p/easyui_tree.html
using System;
using System.Collections.Generic;
namespace TreeUtility
{
/// <summary>
///https://www.codeproject.com/articles/23949/building-trees-from-lists-in-net
/// An object which implements this interface is considered a node in a tree.
/// </summary>
public interface ITreeNode<T>
where T : class
{
/// <summary>
/// A unique identifier for the node.
/// </summary>
int Id
{
get;
}
/// <summary>
/// The parent of this node, or null if it is the root of the tree.
/// </summary>
T Parent
{
get;
set;
}
/// <summary>
/// The children of this node, or an empty list if this is a leaf.
/// </summary>
IList<T> Children
{
get;
set;
}
}
/// <summary>
/// A helper class for objects which implement <see cref="ITreeNode{T}"/>, providing
/// methods to convert flat lists to and from hierarchical trees, iterators, and
/// other utility methods.
/// </summary>
public static class TreeHelper
{
#region Tree structure methods
/// <summary>
/// Converts an array of ITreeNode objects into a forest of trees. The returned list will
/// contain only the root nodes, with each root having a populated <see cref="ITreeNode{T}.Children">Children</see>
/// property.
/// </summary>
/// <param name="flatNodeList">
/// An array of list of node objects, where the <see cref="ITreeNode{T}.Parent">Parent</see>
/// property of each node is either null for root nodes, or an instantiated object with its
/// <see cref="ITreeNode{T}.Id">Id</see> property set.
/// </param>
public static IList<T> ConvertToForest<T>(this IEnumerable<T> flatNodeList)
where T : class, ITreeNode<T>
{
// first, put every TreeNode into a dictionary so that we can easily find tree nodes later.
Dictionary<int, T> dictionary = new Dictionary<int, T>();
foreach (T node in flatNodeList)
{
dictionary.Add(node.Id, node);
// while we're looping, it's a good time to create the Children list
node.Children = new List<T>();
}
// Now, go through each TreeNode. If Parent is null, then it is a root node of a tree,
// so add it to the 'rootNodes' List, which is what will be returned from this method.
// If Parent is not null, then find the parent from the dictionary, and set that to be it's Parent.
List<T> rootNodes = new List<T>();
foreach (T node in flatNodeList)
{
if (node.Parent == null)
{ // this is a root node; add it to the rootNodes list.
rootNodes.Add(node);
}
else
{ // this is not a root node; add it as a child of its parent.
if (!dictionary.ContainsKey(node.Parent.Id))
{
// In this case, this node's parent is not in the flatNodeList.
// By continuing, we are just ignoring this node (it won't be
// returned in the tree). Another option would be to throw an
// exception here.
continue;
}
// make the parent reference for this node a reference to a fully populated parent.
node.Parent = dictionary[node.Parent.Id];
// add this node to the child list of its parent.
node.Parent.Children.Add(node);
}
}
return rootNodes;
}
/// <summary>
/// Converts a heirachacle Array of Tree Nodes into a flat array of nodes. The order
/// of the returned nodes is the same as a depth-first traversal of each tree.
/// </summary>
/// <remarks>The relationships between Parent/Children are retained.</remarks>
public static List<T> ConvertToFlatArray<T>(this IEnumerable<T> trees)
where T : class, ITreeNode<T>
{
List<T> treeNodeList = new List<T>();
foreach (T rootNode in trees)
{
foreach (T node in DepthFirstTraversal(rootNode))
{
treeNodeList.Add(node);
}
}
return treeNodeList;
}
#endregion
#region Search methods
/// <summary>Finds the TreeNode with the given Id in the given tree by searching the descendents.
/// Returns null if the node cannot be found.</summary>
public static T FindDescendant<T>(this T searchRoot, int id)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(searchRoot, "searchRoot");
foreach (T child in DepthFirstTraversal(searchRoot))
{
if (child.Id == id)
{
return child;
}
}
return null;
}
/// <summary>Finds the TreeNode with the given id from the given forest of trees.
/// Returns null if the node cannot be found.</summary>
public static T FindTreeNode<T>(this IEnumerable<T> trees, int id)
where T : class, ITreeNode<T>
{
foreach (T rootNode in trees)
{
if (rootNode.Id == id)
{
return rootNode;
}
T descendant = FindDescendant(rootNode, id);
if (descendant != null)
{
return descendant;
}
}
return null;
}
#endregion
#region Useful tree properties
/// <summary>
/// Checks whether there is a loop from the current node up the tree back to the current node.
/// It is recommended that this is checked to be false before saving the node to your data store.
/// </summary>
/// <example>
/// The most simple example of a hierarchy loop is were there are 2 nodes, "A" and "B", and "A"
/// is "B"'s parent, and "B" is "A"'s parent. This is not allowed, and should not be saved. ,
/// </example>
public static bool HasHeirachyLoop<T>(this T node)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
T tempParent = node.Parent;
while (tempParent != null)
{
if (tempParent.Id == node.Id)
{
return true;
}
tempParent = tempParent.Parent;
}
return false;
}
/// <summary>Returns the root node of the tree that the given TreeNode belongs in</summary>
public static T GetRootNode<T>(this T node)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
T cur = node;
while (cur.Parent != null)
{
cur = cur.Parent;
}
return cur;
}
/// <summary>
/// Gets the depth of a node, e.g. a root node has depth 0, its children have depth 1, etc.
/// </summary>
public static int GetDepth<T>(this T node)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
int depth = 0;
while (node.Parent != null)
{
++depth;
node = node.Parent;
}
return depth;
}
/// <summary>
/// Gets the type of node that the specified node is.
/// </summary>
public static NodeType GetNodeType<T>(this T node)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
if (node.Parent == null)
{
return NodeType.Root;
}
else if (node.Children.Count == 0)
{
return NodeType.Leaf;
}
return NodeType.Internal;
}
#endregion
#region Iterators
/// <summary>
/// Returns an Iterator which starts at the given node, and climbs up the tree to
/// the root node.
/// </summary>
/// <param name="startNode">The node to start iterating from. This will be the first node returned by the iterator.</param>
public static IEnumerable<T> ClimbToRoot<T>(this T startNode)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(startNode, "startNode");
T current = startNode;
while (current != null)
{
yield return current;
current = current.Parent;
}
}
/// <summary>
/// Returns an Iterator which starts at the root node, and goes down the tree to
/// the given node node.
/// </summary>
/// <param name="startNode">The node to start iterating from. This will be the first node returned by the iterator.</param>
public static List<T> FromRootToNode<T>(this T node)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
List<T> nodeToRootList = new List<T>();
foreach (T n in ClimbToRoot(node))
{
nodeToRootList.Add(n);
}
nodeToRootList.Reverse();
return nodeToRootList;
}
/// <summary>
/// Returns an Iterator which starts at the given node, and traverses the tree in
/// a depth-first search manner.
/// </summary>
/// <param name="startNode">The node to start iterating from. This will be the first node returned by the iterator.</param>
public static IEnumerable<T> DepthFirstTraversal<T>(this T startNode)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(startNode, "node");
yield return startNode;
foreach (T child in startNode.Children)
{
foreach (T grandChild in DepthFirstTraversal(child))
{
yield return grandChild;
}
}
}
/// <summary>
/// Returns an Iterator which traverses a forest of trees in a depth-first manner.
/// </summary>
/// <param name="trees">The forest of trees to traverse.</param>
public static IEnumerable<T> DepthFirstTraversalOfList<T>(this IEnumerable<T> trees)
where T : class, ITreeNode<T>
{
foreach (T rootNode in trees)
{
foreach (T node in DepthFirstTraversal(rootNode))
{
yield return node;
}
}
}
/// <summary>
/// Gets the siblings of the given node. Note that the given node is included in the
/// returned list. Throws an <see cref="Exception" /> if this is a root node.
/// </summary>
/// <param name="node">The node whose siblings are to be returned.</param>
/// <param name="includeGivenNode">If false, then the supplied node will not be returned in the sibling list.</param>
public static IEnumerable<T> Siblings<T>(this T node, bool includeGivenNode)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
if (GetNodeType(node) == NodeType.Root)
{
if (includeGivenNode)
{
yield return node;
}
yield break;
}
foreach (T sibling in node.Parent.Children)
{
if (!includeGivenNode && sibling.Id == node.Id)
{ // current node is supplied node; don't return it unless it was asked for.
continue;
}
yield return sibling;
}
}
/// <summary>
/// Traverses the tree in a breadth-first fashion.
/// </summary>
/// <param name="node">The node to start at.</param>
/// <param name="returnRootNode">If true, the given node will be returned; if false, traversal starts at the node's children.</param>
public static IEnumerable<T> BreadthFirstTraversal<T>(this T node, bool returnRootNode)
where T : class, ITreeNode<T>
{
EnsureTreePopulated(node, "node");
if (returnRootNode)
{
yield return node;
}
foreach (T child in node.Children)
{
yield return child;
}
foreach (T child in node.Children)
{
foreach (T grandChild in BreadthFirstTraversal(child, false))
{
yield return grandChild;
}
}
}
#endregion
#region Private methods
[System.Diagnostics.Conditional("DEBUG")]
private static void EnsureTreePopulated<T>(T node, string parameterName)
where T : class, ITreeNode<T>
{
if (node == null)
{
throw new ArgumentNullException(parameterName, "The given node cannot be null.");
}
if (node.Children == null)
{
throw new ArgumentException("The children of " + parameterName + " is null. Have you populated the tree fully by calling TreeHelper<T>.ConvertToForest(IEnumerable<T> flatNodeList)?", parameterName);
}
}
#endregion
}
/// <summary>
/// A type of tree node.
/// </summary>
public enum NodeType
{
/// <summary>
/// A node which is at the root of the tree, i.e. it has no parents.
/// </summary>
Root,
/// <summary>
/// A node which has parent and children.
/// </summary>
Internal,
/// <summary>
/// A node with no children.
/// </summary>
Leaf
}
}
from : https://www.codeproject.com/articles/23949/building-trees-from-lists-in-net
sql:
CREATE TABLE Category ( Id INT IDENTITY(1,1) PRIMARY KEY NOT NULL, [Name] NVARCHAR(20) not NULL, ParentID INT ) GO SELECT Id, [Name], ParentID FROM Category
public class Category
{
private int _id;
private string _name;
private Category _parent;
private List<Category> _children;
public int Id
{
get { return _id; }
set { _id = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public Category Parent
{
get { return _parent; }
set { _parent = value; }
}
public List<Category> Children
{
get { return _children; }
set { _children = value; }
}
}
static List<Category> GetListFromDatabase(DbConnection con) {
DbCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT Id, Name, ParentID FROM Category";
cmd.CommandType = CommandType.Text;
DbDataReader reader = cmd.ExecuteReader();
List<Category> categories = new List<Category>();
foreach (DbDataRecord row in reader) {
Category c = new Category();
c.Id = (int)row["Id"];
c.Name = (string)row["Name"];
if (row["ParentID"] != DBNull.Value)
{
c.Parent = new Category();
c.Parent.Id = (int)row["ParentID"];
}
categories.Add(c);
}
reader.Close();
return categories;
}
public class Category : ITreeNode<Category> {
// contents of class remain as above, because the
// interface is implemented by the Id, Parent, and
// Children properties
}
IList<Category> topLevelCategories =
TreeHelper.ConvertToForest(GetListFromDatabase());
void Page_Load(object sender, EventArgs e) {
IList<Category> topLevelCategories =
TreeHelper.ConvertToForest(Category.GetListFromDatabase());
Response.Write("<ul>");
foreach(Category topLevelCategory in topLevelCategories) {
RenderCategory(topLevelCategory);
}
Response.Write("</ul>");
}
void RenderCategory(Category category) {
Response.Write("<li>" + category.Name);
if (category.Children.Count > 0) {
Response.Write("<ul>");
foreach(Category child in category.Children) {
RenderCategory(child);
}
Response.Write("</ul>");
}
Response.Write("</li>");
}
// in a website, this may use the ASP.NET Cache object.
List<Category> categories = GetCategories();
int categoryId = int.Parse(Request.Params["categoryId"]);
Category currentCategory =
TreeHelper.FindTreeNode(categories, categoryId);
Category currentCategory = GetCategory();
foreach(Category category in
TreeHelper.Iterators.FromRootToNode(currentCategory))
{
Response.Write(" / " + category.Name);
}
List<Category> categories = GetCategories().ConvertToForest();
Category current = categories.FindCategory(3);
foreach(Category descendent in current.DepthFirstTraversal()) {
Response.Write("Depth of " + descendent.Name + ": " + descendent.GetDepth();
}
List<Category> categoryList = Category.GetCategories();
// Get all categories which are not top level categories,
// and retrieve only the name.
var nonRootCategories =
from c in categoryList.DepthFirstTraversalOfList()
where c.Parent != null
select new { Name = c.Name };
// Get all categories at Depth 2, ordered by name, and
// get the whole category object.
var level2Categories =
from c in categoryList.DepthFirstTraversalOfList()
where c.GetDepth() == 2
orderby c.Name ascending
select c;
/// <summary>
/// Geovin Du
/// 涂聚文
/// </summary>
public partial class WebForm11 : System.Web.UI.Page
{
int cc = 0;
int nn = 0;
CategoryBLL bll = new CategoryBLL();
/// <summary>
/// 排序和頁碼設定
/// 塗聚文
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
{
int projectid = 1;
DataTable table = bll.GetList(projectid).Tables[0];
DataRow[] parentMenus = table.Select("ParentId is null", "IdOrder asc");
StringBuilder sb = new StringBuilder();
string unorderedList = GenerateUL(parentMenus, table, sb);
// Response.Write(unorderedList);
this.geovindu.InnerHtml = unorderedList;
//IList<Category> topLevelCategories = TreeHelper.ConvertToForest(list);
//Response.Write("<ul>");
//foreach (Category topLevelCategory in topLevelCategories)
//{
// RenderCategory(topLevelCategory);
//}
//Response.Write("</ul>");
}
/// <summary>
///
/// </summary>
/// <param name="menu"></param>
/// <param name="table"></param>
/// <param name="sb"></param>
/// <returns></returns>
private string GenerateUL(DataRow[] menu, DataTable table, StringBuilder sb)
{
sb.AppendLine("<ul>");
int dispage = table.Rows.Count;
nn = 0;
string line = string.Empty;
if (menu.Length > 0) {
foreach (DataRow dr in menu) {
//Dim handler As String = dr("Handler").ToString()
string menuText = dr["CategoryName"].ToString().Trim();
string page = dr["Id"].ToString();
int pageset = (int)dr["PageSet"];
int strlen =menuText.Length*3;
if ((cc) == 0)
{
string dd = menuText.PadRight(70 - strlen, '.');
line = String.Format("<li><a href='#book1/{0}'>{1}</a>", pageset, dd);
}
else
{
string ss = pageset.ToString().PadLeft(2, '0');
string dd = menuText.PadRight(70 - strlen, '.');
// strlen = dd.Length;
line = String.Format("<li><a href='#book1/{0}'>{1}第{2}頁</a>", pageset, dd, ss,dd.Length-strlen+","+strlen.ToString());
}
sb.Append(line);
string pid = dr["Id"].ToString();
DataRow[] subMenu = table.Select(String.Format("ParentId = {0}", pid),"IdOrder asc");
if (subMenu.Length > 0) {
StringBuilder subMenuBuilder = new StringBuilder();
if (nn == 1)
cc--;
else
cc++;
nn++;
//Response.Write("内二层:"+cc.ToString()+"n:"+nn.ToString()+menuText+"<br/>");
sb.Append(GenerateUL(subMenu, table, subMenuBuilder));
}
cc++;
sb.Append("</li>");
//Response.Write("一层:" + cc.ToString() + menuText + "<br/>");
}
}
sb.Append("</ul>");
// Response.Write("外一层:" + cc.ToString() + "<br/>");
return sb.ToString();
}
/// <summary>
///
/// </summary>
/// <param name="category"></param>
void RenderCategory(Category category)
{
Response.Write("<li>" + category.Name);
if (category.Children.Count > 0)
{
Response.Write("<ul>");
foreach (Category child in category.Children)
{
RenderCategory(child);
}
Response.Write("</ul>");
}
Response.Write("</li>");
}
}
https://forums.asp.net/t/1821996.aspx
https://www.c-sharpcorner.com/UploadFile/rohatash/creating-dynamic-menu-from-database-sql-server-in-Asp-Net/
https://stackoverflow.com/questions/14137811/generate-nested-menu-from-datatable-using-c-sharp-as-ul-list-not-asp-net-menu-co
https://www.codeproject.com/questions/739219/how-to-create-ul-li-dynamically-from-database-usin
浙公网安备 33010602011771号