C# 编程嵌套列表

C# 编程嵌套列表,c#,asp.net,listview,repeater,C#,Asp.net,Listview,Repeater,我正在尝试使用ListView控件在Asp.Net/C#中创建嵌套列表。我看了很多例子,但我似乎没有任何意义 以下是模式: <ul> <li>Item 1 - level 1</li> <li>Item 2 - level 1</li> <li>Item 3 - level 1 <ul> <li>Item 1 - level 2</

我正在尝试使用ListView控件在Asp.Net/C#中创建嵌套列表。我看了很多例子,但我似乎没有任何意义

以下是模式:

<ul>
    <li>Item 1 - level 1</li>
    <li>Item 2 - level 1</li>
    <li>Item 3 - level 1
        <ul>
            <li>Item 1 - level 2</li>
            <li>Item 2 - level 2</li>
            <li>Item 3 - level 2</li>
        </ul>
    </li>
</ul>
  • 项目1-第1级
  • 项目2-第1级
  • 项目3-第1级
    • 项目1-第2级
    • 项目2-第2级
    • 项目3-第2级
我创建了一个列表,它使用一个级别,因此它没有正确地嵌套在html中-只是一个由
  • 标记组成的平面列表

    不过,我想做些改变

    只有一个级别将有一个子菜单-并且一些级别1的项目可能没有任何子项目-因此我正在寻找一个可以呈现0或1个子菜单的模式

    有人知道我需要用下面的代码做什么来实现我想要的吗

    <asp:ListView ID="lv" runat="server"
        OnItemDataBound="LV_ItemDataBound">
        <LayoutTemplate>
            <nav>
                <ul class="content-nav">
                    <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
                </ul>
            </nav>
        </LayoutTemplate>
        <ItemTemplate>
            <li id="liMenuItem" runat="server">
                <asp:HyperLink ID="lnkMenuItem" runat="server"
                CssClass="content-nav_link"></asp:HyperLink>
            </li>
        </ItemTemplate>
    </asp:ListView>
    
            protected void LV_ItemDataBound(object source, ListViewItemEventArgs e)
            {
                var item = e.Item;
    
                if (item.ItemType == ListViewItemType.DataItem)
                {
                    var data = (ContentNavItem)item.DataItem;
    
                    var liMenuItem = item.GetControl<HtmlGenericControl>("liMenuItem");
    
                    // Do something with the item here
                }
            }
    
    void Build()
    {
        var currentId = MenuItems.First(x => x.Route == CurrentUrl).Id;
    
        var currentItems = MenuItems
            .Where(x => x.IsTopLevel || x.ParentId == currentId)
            .OrderBy(x => x.GroupId).ThenBy(x => x.Anchor);
    
        lv.DataSource = currentItems;
        lv.DataBind();
    }
    
    
    
  • 受保护的void LV_ItemDataBound(对象源,ListViewItemEventArgs e) { var项目=e.项目; if(item.ItemType==ListViewItemType.DataItem) { var data=(ContentNavItem)item.DataItem; var liMenuItem=item.GetControl(“liMenuItem”); //对这里的物品做点什么 } } void Build() { var currentId=MenuItems.First(x=>x.Route==CurrentUrl).Id; var currentItems=MenuItems .其中(x=>x.IsTopLevel | | x.ParentId==currentId) .OrderBy(x=>x.GroupId).ThenBy(x=>x.Anchor); lv.DataSource=当前项; lv.DataBind(); }
    使用
    StringBuilder
    将菜单创建为字符串会容易得多。但是如果您真的想要递归控件,您可以克隆该控件并在每个菜单级别重复使用它。我在这个演示中使用了一个转发器,因为它更适合重复项目。首先我们创建一个类和一些演示数据

    public class MenuItem
    {
        public string name { get; set; }
        public List<MenuItem> menuitems { get; set; }
    }
    

    不客气。但是我会递归地构建一个字符串。但我已经发布了一个答案,表明它可以通过控制元素来实现。
    protected void Page_Load(object sender, EventArgs e)
    {
        List<MenuItem> MenuItems = new List<MenuItem>();
    
        for (int i = 0; i < 10; i++)
        {
            MenuItems.Add(new MenuItem() { name = "Name " + i });
    
            if (i == 2 || i == 5 || i == 8)
            {
                MenuItems[i].menuitems = new List<MenuItem>();
                MenuItems[i].menuitems.Add(new MenuItem() { name = "SubName 1" });
                MenuItems[i].menuitems.Add(new MenuItem() { name = "SubName 2" });
                MenuItems[i].menuitems.Add(new MenuItem() { name = "SubName 3" });
    
                if (i == 8)
                {
                    MenuItems[i].menuitems[0].menuitems = new List<MenuItem>();
                    MenuItems[i].menuitems[0].menuitems.Add(new MenuItem() { name = "SubName 1" });
                    MenuItems[i].menuitems[0].menuitems.Add(new MenuItem() { name = "SubName 2" });
                    MenuItems[i].menuitems[0].menuitems.Add(new MenuItem() { name = "SubName 3" });
                }
            }
        }
    
        Repeater1.DataSource = MenuItems;
        Repeater1.DataBind();
    }
    
    <nav>
        <asp:Repeater ID="Repeater1" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
            <HeaderTemplate>
                <ul class="content-nav">
            </HeaderTemplate>
            <ItemTemplate>
                <li id="liMenuItem" runat="server">
                    <%# Eval("name") %>
                    <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
                </li>
            </ItemTemplate>
            <FooterTemplate>
                </ul>
            </FooterTemplate>
        </asp:Repeater>
    </nav>
    
    protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        MenuItem item = e.Item.DataItem as MenuItem;
    
        //check if the item exists and if it has subitems
        if (item != null && item.menuitems != null)
        {
            //determine type and get the properties
            Type type = sender.GetType();
            PropertyInfo[] properties = type.GetProperties();
            Object obj = type.InvokeMember("", BindingFlags.CreateInstance, null, sender, null);
    
            //copy the properties
            foreach (PropertyInfo propertyInfo in properties)
            {
                if (propertyInfo.CanWrite)
                {
                    propertyInfo.SetValue(obj, propertyInfo.GetValue(sender, null), null);
                }
            }
    
            //cast the created object back to a repeater
            Repeater nestedRepeater = obj as Repeater;
    
            //fill the child repeater with the sub menu items
            nestedRepeater.DataSource = item.menuitems;
    
            //attach the itemdatabound event
            nestedRepeater.ItemDataBound += Repeater1_ItemDataBound;
    
            //bind the data
            nestedRepeater.DataBind();
    
            //find the placeholder and add the created Repeater
            PlaceHolder ph = e.Item.FindControl("PlaceHolder1") as PlaceHolder;
            ph.Controls.Add(nestedRepeater);
        }
    }