【问题标题】:Getting Menu Items from database in asp.net从 asp.net 的数据库中获取菜单项
【发布时间】:2012-09-03 04:05:39
【问题描述】:

我正在尝试从 SQL Server 2008 数据库中获取菜单项。

我在 Google 上搜索并找到了这些教程时尝试了类似的方法 first second:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;

namespace MenuDriven
{
    public partial class MenuDB : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            menuBar.MaximumDynamicDisplayLevels = 3;

            if (!IsPostBack)
            {

                SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString);

                con.Open();
                DataSet ds = new DataSet();
                DataTable dt = new DataTable();
                string sql = "Select * from MenuItems";
                SqlDataAdapter da = new SqlDataAdapter(sql, con);
                da.Fill(ds);
                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["MenuLocation"].ToString()));
                }

                foreach (DataRow dr in dt.Select("ParentID >" + 0))
                {
                    MenuItem mnu = new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
                    "", dr["MenuLocation"].ToString());

                    //Code for Multiple Menu Levels
                    string valuePath = getValuePath(Convert.ToInt32(dr["ParentID"].ToString()), dt);
                    //menuBar.FindItem(dr["ParentID"].ToString()).ChildItems.Add(mnu);
                    menuBar.FindItem(valuePath).ChildItems.Add(mnu);**NullReferenceException was handled by the code**
                    //End Code for Multiple Menu Levels
                }
                con.Close();
            }

        }
        private string getValuePath(Int32 Parent, DataTable dt)
        {
            int predecessor = Parent;
            StringBuilder valuePath = new StringBuilder();
            valuePath.Append(Parent.ToString());
            DataRow[] drPar;
            while (true)
            {
                drPar = dt.Select("MenuID=" + predecessor);
                if (drPar[0]["ParentID"].ToString().Equals("0"))**//Index out of range exception**
                    break;
                valuePath.Insert(0, '/');
                valuePath.Insert(0, drPar[0]["ParentID"].ToString());
                predecessor = Convert.ToInt32(drPar[0]["ParentID"].ToString());
            }
            return valuePath.ToString();
        }

    }
}

这段代码有两个错误:

  1. 索引超出范围异常
  2. NullReferenceException 由代码处理

我已经指出了产生错误的代码。

这是我的数据库以及标题。

MenuID  MenuName    MenuLocation    ParentID    Value
1        Parent1      NULL            0             p1
2        Parent2      NULL            0             p2
3        Parent3      NULL            0             p3
11       SubMenuItem1     NULL            1             s1
12       SubMenuItem2     NULL            1             s1
21       SubMenuItem3     NULL            2             s1
111      SubSubMenuItem4  NULL            1             ss1
211      SubSubMenuItem5  NULL            2             ss1

【问题讨论】:

    标签: asp.net c#-4.0 menu


    【解决方案1】:

    我已经为菜单项中的任意数量的级别提供了解决方案。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    
    namespace MenuDriven
    {
        public partial class AnotherMenuTest : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                populateMenuItem();
            }
            private void populateMenuItem()
            {
    
                DataTable menuData = GetMenuData();
                AddTopMenuItems(menuData);
    
            }
    
            private DataTable GetMenuData()
            {
                using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ServerString"].ConnectionString))
                {
                    using (SqlCommand cmd = new SqlCommand("SELECT MenuID,MenuName,ParentID FROM MenuItems", con))
                    {
                        SqlDataAdapter da = new SqlDataAdapter(cmd);
                        DataTable dt = new DataTable();
                        da.Fill(dt);
                        return dt;
                    }
    
                }
            }
    
            /// Filter the data to get only the rows that have a
            /// null ParentID (This will come on the top-level menu items)
    
            private void AddTopMenuItems(DataTable menuData)
            {
                DataView view = new DataView(menuData);
                view.RowFilter = "ParentID = 0";
                foreach (DataRowView row in view)
                {
                    MenuItem newMenuItem = new MenuItem(row["MenuName"].ToString(), row["MenuID"].ToString());
                    menuBar.Items.Add(newMenuItem);
                    AddChildMenuItems(menuData, newMenuItem);
                }
    
            }
    
            //This code is used to recursively add child menu items by filtering by ParentID
    
            private void AddChildMenuItems(DataTable menuData, MenuItem parentMenuItem)
            {
                DataView view = new DataView(menuData);
                view.RowFilter = "ParentID=" + parentMenuItem.Value;
                foreach (DataRowView row in view)
                {
                    MenuItem newMenuItem = new MenuItem(row["MenuName"].ToString(), row["MenuID"].ToString());
                    parentMenuItem.ChildItems.Add(newMenuItem);
                    AddChildMenuItems(menuData, newMenuItem);
                }
            }
        }
    }
    

    感谢 KnowledgeSeeker 和 Antonio 的回复。

    数据库是这样的。

    这是我的数据库以及标题。

    MenuID  MenuName    MenuLocation    ParentID    
    1          Parent1             NULL           0             
    2          Parent2             NULL           0             
    3          Parent3             NULL           0             
    11         SubMenuItem1    NULL           1             
    12         SubMenuItem2    NULL           1             
    21         SubMenuItem3    NULL           2             
    111        SubSubMenuItem4     NULL           1             
    211        SubSubMenuItem5     NULL           2         
    

    解决方案是: 在数据库本身内设置父节点。

    例如:插入 dbo.MenuItems 值(333,'SubSubMenuItem8',NULL,21)

    这会将SubSubMenuItem8 设置为父节点SubMenuItem3 的子节点

    【讨论】:

      【解决方案2】:

      按照以下示例修改您的代码。我正在使用following 菜单。它正在工作您可能需要根据需要修改代码

                  String sqlQuery = "SELECT * FROM pMenuItems";
      
                  dsMenu = DataProvider.Connect_Select(sqlQuery);
      
                  DataTable tableMenu = dsMenu.Tables[0];
                  DataView dvMenu = new DataView(tableMenu);
                  //dvMenu.RowFilter = "PageInheritance is NULL";
                  dvMenu.RowFilter = "PageInheritance = 0";
                  int dsMenuRowCount = dsMenu.Tables[0].Rows.Count;
                  //Create Top Menu
                  //StringBuilder sb = new StringBuilder();
                  StringBuilder sbMenuFooter = new StringBuilder();
                  if (dsMenu != null && dsMenu.Tables.Count > 0 && dsMenu.Tables[0].Rows.Count > 0)
                  {
                      foreach (DataRowView row in dvMenu)
                      {
                         // MenuItem menuItem = new MenuItem(row["MenuName"].ToString().ToUpper(), row["MenuID"].ToString());
                          MenuItem menuItem = new MenuItem(row["PageName"].ToString(), row["PageId"].ToString());
                          bool PageInternalLink = bool.Parse(row["PageInternalLink"].ToString());
                          if (PageInternalLink == true)
                          {
                              menuItem.NavigateUrl = row["PageURL"].ToString() + "?PageId=" + row["PageId"];
                          }
                          else
                          {
                              menuItem.NavigateUrl = row["PageURL"].ToString();
                              menuItem.Target = row["PageWindow"].ToString();
                          }
                          //menuItem.Target = 
                          Menu1.Items.Add(menuItem);
                          AddChildItems(tableMenu, menuItem, PageInternalLink );
                      }
      
      private static void AddChildItems(DataTable table, MenuItem menuItem, bool PageInternalLink)
      {
          DataView viewItem = new DataView(table);
          viewItem.RowFilter = "PageInheritance = " + menuItem.Value;
          //foreach (DataRowView row in dvMenu)
          foreach (DataRowView childView in viewItem)
          {
              MenuItem childItem = new MenuItem(childView["MenuName"].ToString(), childView["MenuID"].ToString());
              childItem.NavigateUrl = childView["PageURL"].ToString() + "?PageId=" + childView["PageId"];
              if (PageInternalLink == true)
              {
                  childItem.NavigateUrl = childView["PageURL"].ToString() + "?PageId=" + childView["PageId"];
              }
              else
              {
                  childItem.NavigateUrl = childView["PageURL"].ToString();
                  childItem.Target = childView["PageWindow"].ToString();
              }
              menuItem.ChildItems.Add(childItem);
              AddChildItems(table, childItem, PageInternalLink);
          }
      
      
      }
      

      HTML

       <script type="text/javascript">
          $(document).ready(function () {
              $('#<%=Menu1.ClientID %> ul', '#<%=Menu1.ClientID %> li').removeClass();
          });
          $(document).ready(function () {
              $("#dMenuContainer").delay(500).fadeIn(500);
              $('#smoothmenu1 ul, #smoothmenu1 li').removeClass();
          });
          ddsmoothmenu.init({
              mainmenuid: "<%=Menu1.ClientID %>", //menu DIV id
              orientation: 'h', //Horizontal or vertical menu: Set to "h" or "v"
              classname: 'ddsmoothmenu', //class added to menu's outer DIV
              customtheme: ["", ""], //78AC1B
              contentsource: "markup" //"markup" or ["container_id", "path_to_menu_file"]
          })
      </script>
      ...
          <table align="center" cellpadding="0" cellspacing="0" align="center" >
              <tr>
                  <td align="center" valign="middle"><div id="smoothmenu1" class="ddsmoothmenu">
                       <asp:Menu ID="Menu1"  runat="server"  Orientation="Horizontal" CssClass="ddsmoothmenu" IncludeStyleBlock="False" DisappearAfter="500" >
      
                       </asp:Menu> 
                       </div>
                  </td>
              </tr>
          </table>
      

      【讨论】:

      • Knowledge Seeker,我需要获取 ASP MENU 的值,而不是 li ui 元素的值,因为我已经看到了您使用的菜单。
      • 您只需要根据需要修改代码并从我提到的链接下载 Jquery 文件和 JS 文件以及 css。相信我,我尝试了与您尝试相同的方法,但遇到了各种麻烦。这个菜单脚本很灵活,可以嵌套到 n 级..
      • 如果你想测试,那么只使用下面的代码作为默认 css ` `
      【解决方案3】:

      您必须按 ParentID 对数据进行排序,然后循环槽表,并为每个项目找到父项目并将其添加到它的 ChildItems,如果您没有找到父项将项目添加到根。

      获取数据:

      string sql = "Select * from MenuItems Order By ParentID";
      DataTable data = GetTable(sql);
      

      然后填充菜单:

        foreach (DataRow rw in data.Rows)
        {
          IEnumerable<MenuItem> menuItems = Extensions.GetItems<MenuItem>(menuBar.Items, item => item.ChildItems);
      
          MenuItem parent = menuItems.FirstOrDefault(mi => mi.Value == rw.Field<int>("ParentID").ToString());
          MenuItem newItem = new MenuItem(rw.Field<string>("MenuName"), rw.Field<int>("MenuID").ToString());
          if (parent == null)
            menuBar.Items.Add(newItem);
          else
            parent.ChildItems.Add(newItem);
        }
      

      这里是返回所有树节点的 GetItems 方法,取自这里:https://stackoverflow.com/a/1815600/351383

       public static class Extensions
        {
          public static IEnumerable<T> GetItems<T>(this IEnumerable collection, Func<T, IEnumerable> selector)
          {
            Stack<IEnumerable<T>> stack = new Stack<IEnumerable<T>>();
            stack.Push(collection.OfType<T>());
      
            while (stack.Count > 0)
            {
              IEnumerable<T> items = stack.Pop();
              foreach (var item in items)
              {
                yield return item;
      
                IEnumerable<T> children = selector(item).OfType<T>();
                stack.Push(children);
              }
            }
          }
        }
      

      【讨论】:

      • Antonio 我可以看到第二级元素的输出,但我看不到第三级菜单项的输出。它抛出错误说明“空引用异常”
      • 你的 getValuePath 返回 null,尝试调试它看看为什么。但试试这个解决方案,它会简单得多,并且适用于无限数量的关卡
      • 我找不到它给出的错误。还有什么是你的代码中的mainMenu
      • 它在MenuItem newItem = new MenuItem(rw.Field&lt;string&gt;("MenuName"), rw.Field&lt;int&gt;("MenuID").ToString());这一行抛出错误,指出Specified cast is not valid.
      • 您的数据库中的 MenuID 字段是什么类型?如果是字符串,则输入 rw.Field("MenuID") 或者您可能在该字段中有 null ?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 2016-04-29
      相关资源
      最近更新 更多