0

SQL Server 2008 データベースからメニュー項目を取得しようとしています。

私はグーグルで調べて、これらのチュートリアルを最初2番目に見つけたので、このようなことを試しました :

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

    }
}

このコードには 2 つのエラーがあります。

  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
4

3 に答える 3

3

メニュー項目の任意の数のレベルに対する解決策があります。

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

于 2012-09-11T05:21:41.207 に答える
1

以下の例に従ってコードを変更します。以下のメニューを使用し ています。機能しています 必要に応じてコードを変更する必要がある場合があります

            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>
于 2012-09-10T10:39:27.400 に答える
0

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 メソッドを次に示します。

 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);
        }
      }
    }
  }
于 2012-09-10T10:29:23.740 に答える