使用 c# 作为 ul 列表而不是 Asp.net 菜单控件从数据表生成嵌套菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14137811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:48:05  来源:igfitidea点击:

Generate Nested Menu from datatable using c# as ul list not Asp.net Menu control

c#asp.nethtml-lists

提问by Learning

I need to generate a custom menu which has submenu's using list ul from the DataTable

我需要生成一个自定义菜单,其中包含使用列表 ul 的子菜单 DataTable

Below is the sample of Database and sample HTML ul list with dummy data.

下面是数据库示例和带有虚拟数据的示例 HTML ul 列表。

PID         MENU                 Handler                  PageLangID  ParentID    IssueID     CatID       MenuPosition
----------- -------------------- ------------------------ ----------- ----------- ----------- ----------- ------------

6           Business             Category.aspx    1           6           1           16          1
6           Culture              Category.aspx    1           6           1           3           1
6           Economy              Category.aspx    1           6           1           2           1
6           Finance              Category.aspx    1           6           1           19          1
6           Infrastructure       Category.aspx    1           6           1           17          1
6           Lifestyle            Category.aspx    1           6           1           20          1
6           Others               Category.aspx    1           6           1           21          1
6           People               Category.aspx    1           6           1           7           1
6           Politics             Category.aspx    1           6           1           1           1
6           Sports               Category.aspx    1           6           1           4           1
12          1002                  Default.aspx             1           12          3           1           1
12          1003                  Default.aspx             1           12          4           1           1
12          1006                  Default.aspx             1           12          1           1           1
12          1009                  Default.aspx             1           12          5           1           1
1           Home                 Default.aspx             1           0           1           1           10
11          Video                Videos.aspx              1           10          1           1           10
2           About Us             Page.aspx                1           0           1           1           20
5           Articles             Articles.aspx            1           0           1           1           20
6           Categories           Category.aspx    1           0           

DESIRED HTML OUTPUT

所需的 HTML 输出

<div id="nav-wrapper">
<ul id="nav" class="dropdown dropdown-linear"  >
    <li><span class="dir"><a href="./">Home</a></span></li>
    <li ><span class="dir"><a href="ultimate.linear.html">About Us</a></span>
        <ul >
            <li><a href="./">History</a></li>
            <li><a href="./">Our Vision</a></li>
            <li><a href="./">The Team</a></li>
            <li><a href="./">Clients</a></li>
            <li><a href="./">Testimonials</a></li>
            <li><a href="./">Press</a></li>
            <li><a href="./">FAQs</a></li>
        </ul>
    </li>

    <li class="active" ><span class="dir"><a href="ultimate.linear-active.html">Categories</a></span>
        <ul>
            <li><a href="./">Politics</a></li>
            <li><a href="./">Economy</a></li>
            <li><a href="./">Finance</a></li>
            <li><a href="./">Business</a></li>
            <li><a href="./">Group News</a></li>
            <li><a href="./">Culture</a></li>
            <li><a href="./">Lifestyle</a></li>
            <li><a href="./">Sports</a></li>
            <li><a href="./">Infrastructure</a></li>
            <li><a href="./">Book Review</a></li>   
            <li><a href="./">Others</a></li>                
        </ul>
    </li>
</ul>
</div> 

I don't want to use nested repeater controls. I would appreciate sample code which i can work with.

我不想使用嵌套的中继器控件。我很感激我可以使用的示例代码。

UPDATED: This code doesn't work, definitely i am doing something wrong

更新:此代码不起作用,我肯定做错了什么

protected void Page_Load(object sender, EventArgs e)
{

    DataSet ds = new DataSet();
    ds = DataProvider.Connect_Select(strSql);
     DataTable dt = ds.Tables[0];

    //dt.Select("ParentID == 0") ;
    var s = GenerateUL(dt.Select("ParentID == 0"));
    Response.Write(s);

}


private string GenerateUL(var menus)
{
    var sb = new StringBuilder();

    sb.AppendLine("<ul>");
    foreach (var menu in menus)
    {
        if (menu.Menus.Any())
        {
            sb.AppendLine("<li>" + menu.Text);
            sb.Append(GenerateUL(menu.Menus.AsQueryable()));
            sb.AppendLine("</li>");
        }
        else
            sb.AppendLine("<li>" + menu.Text + "</li>");
    }
    sb.AppendLine("</ul>");

    return sb.ToString();
}

LATEST UPDATE BASED ON DANI SOLUTION

基于 DANI 解决方案的最新更新

It seems to work fine with his data sample but when i use it with my actual data it generate StackOverflowException was unhandled.

他的数据样本似乎可以正常工作,但是当我将它与我的实际数据一起使用时,它生成的 StackOverflowException 未得到处理。

Below is the screen shot of the error. enter image description here

下面是错误的屏幕截图。 在此处输入图片说明

Error is generated when it goes into sort of infinate loop where PID=6My actual data which is show above has 23 records & is result of UNION from different tabel that is the reason i have multiple rows in table where PID=6i am afraid it will also do same where pid=12.

当它进入某种无限循环时会产生错误,其中PID=6我上面显示的实际数据有 23 条记录,并且是来自不同表格的 UNION 结果,这就是我在表格中有多行的原因,PID=6我担心它也会在何处执行相同的操作pid=12.

Even if i catch the exception my website still crash due to this ...

即使我捕捉到异常,我的网站仍然因为这个而崩溃......

Latest CODE

最新代码

protected void Page_Load(object sender, EventArgs e)
{
    string strSql = "SELECT DISTINCT PID, MENU, Handler,PageLangID, ParentID,IssueID, CatID,MenuPosition FROM MENUTABLE ";

    DataSet ds = new DataSet();
    ds = DataProvider.Connect_Select(strSql);
    DataTable table = ds.Tables[0];
    DataRow[] parentMenus = table.Select("ParentId = 0");
         var sb = new StringBuilder();
         string unorderedList = GenerateUL(parentMenus, table, sb);
    }

    private string GenerateUL(DataRow[] menu, DataTable table, StringBuilder sb)
    {
    sb.AppendLine("<ul>");

    try
    {

        if (menu.Length > 0)
        {
            foreach (DataRow dr in menu)
            {
                ctr = ctr + 1;
                string handler = dr["Handler"].ToString();
                string menuText = dr["MENU"].ToString();
                string line = String.Format(@"<li><a href=""{0}"">{1}</a>", handler, menuText);
                sb.Append(line);

                string pid = dr["PID"].ToString();

                DataRow[] subMenu = table.Select(String.Format("ParentId = {0}", pid));
                if (subMenu.Length > 0)
                {
                    var subMenuBuilder = new StringBuilder();
                    sb.Append(GenerateUL(subMenu, table, subMenuBuilder));
                }
                sb.Append("</li>");
            }
        }
    }
    catch (Exception ex)
    {
    }

    sb.Append("</ul>");
    return sb.ToString();
}

Update: When i change my query which get me result below then it works fine, but it would be good to make it work on actual data which is shown first in the question.

更新:当我更改我的查询得到下面的结果时,它可以正常工作,但最好让它在问题中首先显示的实际数据上工作。

PID         MENU                 Handler                  PageLangID  ParentID    IssueID     CatID       MenuPosition
----------- -------------------- ------------------------ ----------- ----------- ----------- ----------- ------------
1           Home                 Default.aspx             1           0           1           1           10
2           About Us             Page.aspx                1           0           1           1           20
3           News                 News.aspx                1           0           1           1           30
5           Articles             Articles.aspx            1           0           1           1           20
6           Categories           Category.aspx    1           0           1           1           25

采纳答案by Denys Wessels

I've created a slightly simpler table structure on my side as we only need the following columns for the sake of example :

我在我这边创建了一个稍微简单的表结构,因为我们只需要以下列作为示例:

  1. PID
  2. MENU
  3. Handler
  4. ParentID
  1. PID
  2. 菜单
  3. 处理程序
  4. 家长ID

Sample data:

样本数据:

As you can see from this example we have a 3 way deep hierarchy for Product and the rest of the items have no children.

正如你从这个例子中看到的,我们有一个 3 向深的产品层次结构,其余的项目没有子项。

enter image description here

在此处输入图片说明

Code behind:

后面的代码:

The code below does the following:

下面的代码执行以下操作:

  1. First gets all items with no parents and starts looping through them
  2. Checks whether an item is a parent to any node and gets its children recursively.

    protected void Page_Load(object sender, EventArgs e)
    {
        DataSet ds = new DataSet();
        ds = DataProvider.Connect_Select("SELECT * FROM Menu");
        DataTable table = ds.Tables[0];
        DataRow[] parentMenus = table.Select("ParentId = 0");
    
        var sb = new StringBuilder();
        string unorderedList = GenerateUL(parentMenus, table,sb);
        Response.Write(unorderedList);
    }
    
    private string GenerateUL(DataRow[] menu,DataTable table,StringBuilder sb)
    {
        sb.AppendLine("<ul>");
    
        if (menu.Length > 0)
        {
            foreach (DataRow dr in menu)
            {
                string handler = dr["Handler"].ToString();
                string menuText = dr["MENU"].ToString();
                string line = String.Format(@"<li><a href=""{0}"">{1}</a>",handler,menuText);
                sb.Append(line);
    
                string pid = dr["PID"].ToString();
    
                DataRow[]subMenu = table.Select(String.Format("ParentId = {0}", pid));
                if (subMenu.Length > 0)
                {
                    var subMenuBuilder = new StringBuilder();
                    sb.Append(GenerateUL(subMenu, table, subMenuBuilder));
                }
                sb.Append("</li>");
            }
        }
    
        sb.Append("</ul>");
        return sb.ToString();
    }
    
  1. 首先获取所有没有父项的项并开始遍历它们
  2. 检查项是否是任何节点的父项并递归获取其子项。

    protected void Page_Load(object sender, EventArgs e)
    {
        DataSet ds = new DataSet();
        ds = DataProvider.Connect_Select("SELECT * FROM Menu");
        DataTable table = ds.Tables[0];
        DataRow[] parentMenus = table.Select("ParentId = 0");
    
        var sb = new StringBuilder();
        string unorderedList = GenerateUL(parentMenus, table,sb);
        Response.Write(unorderedList);
    }
    
    private string GenerateUL(DataRow[] menu,DataTable table,StringBuilder sb)
    {
        sb.AppendLine("<ul>");
    
        if (menu.Length > 0)
        {
            foreach (DataRow dr in menu)
            {
                string handler = dr["Handler"].ToString();
                string menuText = dr["MENU"].ToString();
                string line = String.Format(@"<li><a href=""{0}"">{1}</a>",handler,menuText);
                sb.Append(line);
    
                string pid = dr["PID"].ToString();
    
                DataRow[]subMenu = table.Select(String.Format("ParentId = {0}", pid));
                if (subMenu.Length > 0)
                {
                    var subMenuBuilder = new StringBuilder();
                    sb.Append(GenerateUL(subMenu, table, subMenuBuilder));
                }
                sb.Append("</li>");
            }
        }
    
        sb.Append("</ul>");
        return sb.ToString();
    }
    

End result:

最终结果:

enter image description here

在此处输入图片说明

EDIT:

编辑:

The problem is that the code constructs the menu based on ParentID's and for ID=6 the ParentID also happens to be 6. So 6 calls 6 and we have an endless loop,great.

问题是代码基于 ParentID 构建菜单,对于 ID=6,ParentID 也恰好是 6。所以 6 调用 6 并且我们有一个无限循环,太好了。

Now that we know what the issue is, we can put in a simple check to construct sub menus recursively only if ParentId != PID, here's the updated code:

现在我们知道问题是什么,我们可以进行简单的检查以递归构造子菜单,只有当ParentId != PID,这里是更新的代码:

private string GenerateUL(DataRow[] menu, DataTable table, StringBuilder sb)
{
    sb.AppendLine("<ul>");

    if (menu.Length > 0)
    {
        foreach (DataRow dr in menu)
        {
            string handler = dr["Handler"].ToString();
            string menuText = dr["MENU"].ToString();
            string line = String.Format(@"<li><a href=""{0}"">{1}</a>", handler, menuText);
            sb.Append(line);

            string pid = dr["PID"].ToString();
            string parentId = dr["ParentId"].ToString();

            DataRow[] subMenu = table.Select(String.Format("ParentId = {0}", pid));
            if (subMenu.Length > 0 && !pid.Equals(parentId))
            {
                var subMenuBuilder = new StringBuilder();
                sb.Append(GenerateUL(subMenu, table, subMenuBuilder));
            }
            sb.Append("</li>");
        }
    }
    sb.Append("</ul>");
    return sb.ToString();
}

I think the important thing here is to actually understand how this code works by stepping through it in the debugger, that way you'll be able to change if any other issues come up.

我认为这里重要的是通过在调试器中逐步执行来实际了解这段代码的工作原理,这样如果出现任何其他问题,您就可以进行更改。