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

标签 c# asp.net html-lists

我需要使用 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。

下面是错误的屏幕截图。 enter image description here

当它进入某种无限循环时会生成错误,其中 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

最佳答案

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

  1. PID
  2. 菜单
  3. 负责人
  4. parent 身份

示例数据:

正如您从这个例子中看到的,我们有一个 3 层的 Product 层次结构,其余项目没有子项。

enter image description here

代码隐藏:

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

  1. 首先获取所有没有 parent 的项目并开始遍历它们
  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();
    }
    

最终结果:

enter image description here

编辑:

问题是代码根据 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();
}

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

关于c# - 使用 c# 作为 ul 列表而不是 Asp.net 菜单控件从数据表生成嵌套菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14137811/

相关文章:

c# - 禁用搜索 GAC

c# - 使用 DotNetOpenAuth 从 OpenID 提供商获取电子邮件地址

c# - 如何将匿名对象转换为键/值对或 HTML 属性?

c# - 数据绑定(bind)误解

css - 如何创建一个无序列表,用内联图像替换文本

c# - 使用反射在某些操作系统上使用命名空间

c# - 在 asp.net 代码隐藏页面中添加 <br/> 和 <hr/>

ASP.NET 开发服务器 - 日志文件位置

css - 如何在不使用任何图像或 span 标签的情况下通过 CSS 在 UL/LI html 列表中设置元素符号颜色

html - 链接在左右浮动但在高度居中对齐的菜单