【问题标题】:Generate Nested Menu from datatable using c# as ul list not Asp.net Menu control使用 c# 从数据表生成嵌套菜单作为 ul 列表而不是 Asp.net 菜单控件
【发布时间】:2012-12-17 18:00:44
【问题描述】:

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

下面是数据库示例和带有虚拟数据的示例 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           

所需的 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> 

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

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

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();
}

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

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

以下是错误的屏幕截图。

当它进入PID=6的无限循环时会生成错误我上面显示的实际数据有23条记录&是来自不同表格的UNION的结果,这就是我在PID=6的表格中有多行的原因恐怕它也会在pid=12 的地方做同样的事情。

即使我发现异常,我的网站仍然会因此崩溃...

最新代码

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();
}

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

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

【问题讨论】:

  • 这个已经问过了,你可以在下面的链接stackoverflow.com/questions/3485434/…看到这个
  • @Mayur,看起来是一个很好的解决方案,但我无法理解它,因为它使用 LINQ 和 DataClasses1DataContext 。我需要它来使用 c# 的 asp.net-webform
  • 删除 Dataclass1datacontext 和上下文,而不是上下文,您可以使用 myDataTable.Select("ParentID == 0") 而不是 IQueryable 菜单,您可以使用 var 菜单。
  • @Mayur,感谢您的帮助,我已经更新了问题,但它不起作用我在代码中做错了什么。

标签: c# asp.net html-lists


【解决方案1】:

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

  1. PID
  2. 菜单
  3. 处理程序
  4. 父母ID

样本数据:

从这个例子中可以看出,我们有一个 3 层的 Product 层次结构,其余的项没有子项。

背后的代码:

以下代码执行以下操作:

  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();
    }
    

最终结果:

编辑:

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

现在我们知道问题出在哪里,我们可以进行一个简单的检查,仅当 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();
}

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

【讨论】:

  • 感谢您的解决方案,这似乎是一个可行的解决方案,但在我实施您的解决方案后,它正在生成StackOverFlowException。我注意到我无休止地进入循环,出于某种原因我正在调试它,我的表中实际上有 23 行,我认为它可能会循环 23 次,但它循环的次数更多,并且在 pid=6 的地方产生错误,我会更新我的问题和错误截图供参考。无论如何,我很欣赏你的解决方案,希望你能为我解决这个迷雾
  • 我已经进行了更新。试一试,让我知道它是否解决了您的问题!如果我的帖子对您​​有帮助,请标记为已回答
  • @Dani,谢谢它现在也可以根据需要使用重复的 PID。感谢您的帮助。我相信这段代码会帮助很多人,因为我找不到适用于数据表的类似代码。很好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多