C# asp.net中来自数据库的菜单控件

C# asp.net中来自数据库的菜单控件,c#,asp.net,sql,C#,Asp.net,Sql,我的母版页中有一个菜单控件。菜单的名称和相应的url来自数据库。如果菜单有子菜单,它也会正确显示。 但是如果子菜单有子菜单,问题就会出现。 我的数据库表有4列 MenuId | | MenuName | | | ParentId | | URL 代码是 private void getMenu() { DataSet ds = new DataSet(); DataTable dt = new DataTable(); ds = objSec.ShowMenu(

我的母版页中有一个菜单控件。菜单的名称和相应的url来自数据库。如果菜单有子菜单,它也会正确显示。 但是如果子菜单有子菜单,问题就会出现。 我的数据库表有4列 MenuId | | MenuName | | | ParentId | | URL

代码是

 private void getMenu()
 {
     DataSet ds = new DataSet();
     DataTable dt = new DataTable();
     ds = objSec.ShowMenu(s_UserId);

     dt = ds.Tables[0];
     DataRow[] drowpar = dt.Select("ParentID=" + 0);

     foreach (DataRow dr in drowpar)
     {
         menuBar.Items.Add(new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
         "", dr["URL"].ToString()));
     }

     foreach (DataRow dr in dt.Select("ParentID >" + 0))
     {
         try
         {
             MenuItem mnu = new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
              "", dr["URL"].ToString());
              menuBar.FindItem(dr["ParentID"].ToString()).ChildItems.Add(mnu);
         }
         catch (Exception ex)
         {                  
         }
      }
    }

如果表中的子项位于其父项之前,则示例中的方法可能会导致不正确的结果。此外,空的catch块可能会隐藏任何错误。因此,我推荐另一种方法

您也可以使用递归来填充控件,而不是循环表。这将删除重复代码的数量:

private void getMenu()
{
    DataSet ds = objSec.ShowMenu(s_UserId);
    DataTable dt = ds.Tables[0];
    AddMenuItems(dt, 0, menu.Items);
}

private void AddMenuItems(DataTable dt, int parentId, MenuItemCollection items)
{
    DataRow[] rows = dt.Select("ParentID=" + parentId.ToString());
    foreach(var dr in rows)
    {
        var id = (int) dr["MenuID"];
        var menuItem = new MenuItem(dr["MenuName"].ToString(), id.ToString(),
                                    "", dr["URL"].ToString());
        items.Add(menuItem);
        // Add subitems
        AddMenuItems(dt, id, menuItem.ChildItems); 
    }
}
该示例首先调用顶级项ParentID=0的AddMenuItems方法。添加每个项后,通过再次调用AddMenuItems方法添加其子项,因此术语为recursive,提供顶级项的id作为父项。对于每个第二级子级,将再次调用该方法,以此类推