我正在尝试从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();
}
}
}
我从这段代码中得到两个错误:
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
答案 0 :(得分: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
解决方案是: 在数据库本身中设置父节点。
Ex:插入dbo.MenuItems值(333,'SubSubMenuItem8',NULL,21)
这会将SubSubMenuItem8
作为子节点设置为父节点SubMenuItem3
答案 1 :(得分:1)
按照以下示例修改代码。我正在使用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>
答案 2 :(得分:0)
您必须按ParentID对数据进行排序,然后循环使用表格,并为每个项目找到父项目,并将其添加到其ChildItems,如果您没有找到父项目添加到root。
获取数据:
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);
}
}
}
}