如何在C#中使用唯一ID构建递归菜单?

时间:2015-07-01 07:51:10

标签: c# asp.net

我需要构建一个id如下所示的菜单树,我尝试下面的代码,首先构建一个树,但不返回预期的输出。 任何人都可以帮忙怎么做?

下面是一个如何使用id

排列项目的示例
<ul>
    <li id = "1">Office</li>
    <li id = "2">Home
        <ul>
            <li id = "2-1">Bed</li>
            <li id = "2-2">Pillow</li>
        </ul>
    </li>
    <li id = "3">School
        <ul>
            <li id = "3-1">Class
                <ul>
                    <li id = "3-1-1">Grade</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

List<Node> _nodes = new List<Node>();
_nodes.Add(new Node() { id = 1, parentid = 0, name = "Office" });
_nodes.Add(new Node() { id = 2, parentid = 0, name = "Home" });
_nodes.Add(new Node() { id = 3, parentid = 2, name = "Bed" });
_nodes.Add(new Node() { id = 4, parentid = 2, name = "Pillow" });
_nodes.Add(new Node() { id = 6, parentid = 0, name = "School" });
_nodes.Add(new Node() { id = 7, parentid = 6, name = "Class" });
_nodes.Add(new Node() { id = 8, parentid = 7, name = "Grade" });

private static string RenderMenu(List<Node> nodes)
{
    StringBuilder menu = new StringBuilder();

    if (nodes.Count > 0)
    {
        menu.AppendLine("<ul>");
        foreach (Node _n in nodes)
        {
            menu.AppendLine("<li>");
            if (_n.parentid != 0)
                menu.AppendLine(RenderMenu(nodes.Where(p => p.parentid == _n.parentid).ToList()));
            else
                menu.AppendLine(_n.name);
            menu.AppendLine("</li>");
        }
        menu.AppendLine("</ul>");
    }
    return menu.ToString();
}

2 个答案:

答案 0 :(得分:1)

你有一个树形结构,但你把它画成一个普通的结构。

我的意思是,您的foreach (Node _n in nodes)会产生<li>与您List<Node>中的项目一样多的id。这不是你想要的。

传递List<Node>代替List会更合乎逻辑,更方便,因为您不知道哪些项目会被呈现,因此您需要在每个时刻都需要整个id在下一个子菜单中。

现在关于唯一ID。我建议您使用与List<Node>中相同的List s。它更容易,并且保证它们是唯一的(否则,我们根本无法构建菜单)。您需要存储它的完整路径。 有一个很好的选择 - 使用id作为函数参数传递数组\ Stack<int>。但是,具有Node id的全球public static List<Node> _nodes; public static Stack<int> _currentPath; public static string RenderMenu(int id) { var currentChildNodes = _nodes.Where(x => x.parentid == id).ToArray(); if (currentChildNodes == 0) return String.Empty; // No children - no submenu! StringBuilder menu = new StringBuilder(); menu.AppendLine("<ul>"); foreach (var currentChildNode in currentChildNodes) { _currentPath.Push(currentChildNode.id); menu.AppendLine(String.Format("<li id='{0}'>{1}{2}</li>", String.Join('-', Array.Reverse(_currentPath.ToArray())), currentChildNode.name, RenderMenu(currentChildNode.id)); _currentPath.Pop(); // Keep in mind that if currentChildNode does not have child nodes // then RenderMenu() will return String.Empty and result will be "<li>name</li>" } menu.AppendLine("</ul>"); return menu.ToString(); } // Somewhere in code RenderMenu(0); 是一个不错的选择。 每次你“输入”一个节点 - 你把它添加到堆栈,每次你“离开”它 - 你删除一个项目。在任何时候,你都有实际的递归路径。

这就是我如何解决这个问题:

int

如果由于某种原因,您需要生成后续的for (int i = 0; i < currentChildNodes.Count; i++) // Convert to for-loop { var currentChildNode = currentChildNodes[i]; _currentPath.Push(i + 1); // Change node.id to i menu.AppendLine(String.Format("<li id='{0}'>{1}{2}</li>", String.Join('-', _currentPath.ToArray()), currentChildNode.name, RenderMenu(currentChildNode.id)); _currentPath.Pop(); // Keep in mind that if currentChildNode does not have child nodes // then RenderMenu() will return String.Empty and result will be "<li>name</li>" } ID,则可以通过以下方式更改循环:

{{1}}

答案 1 :(得分:1)

string menu = OrganizeMenu(_nodes);

private static string OrganizeMenu(List<Node> nodes)
{
    menu.Append("<ul>"); // start the List
    List<Node> parentNode = nodes.Where(item => item.parentid == 0).ToList(); // Get all Parent Node (Root Node i.e. a Node with parentid = 0)
    List<Node> childNode = nodes.Except(parentNode).ToList(); // Get all Child Node (i.e. a Node with parentid != 0)

    foreach (var pNode in parentNode) // traverse for each Parent Node and add this to root level
    {
        menu.Append("<li>"); 
        menu.Append(pNode.name);
        GetChilds(nodes, pNode);
        menu.Append("</li>");
    }

    menu.Append("</ul>"); // end the list

    return menu.ToString();
}

private static void GetChilds(List<Node> nodes, Node parentNode)
{
    List<Node> childs = nodes.Where(item=> item.parentid == parentNode.id).ToList();
    foreach (var child in childs)
    {
        menu.Append("<ul>");
        menu.Append(child.name);
        GetChilds(nodes, child);
        menu.Append("</ul>");
    }
}