首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >程序化嵌套列表

程序化嵌套列表
EN

Stack Overflow用户
提问于 2018-08-13 20:51:14
回答 1查看 527关注 0票数 0

我正在尝试使用ListView控件在Asp.Net/C#中创建嵌套列表。我看了很多例子,但我似乎无法理解它们。

模式是这样的:

代码语言:javascript
复制
<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>

我已经创建了一个列表,它使用了一个单独的级别,所以它不能很好地嵌套到html中--它只是一个<li>标签的平面列表。

然而,我想做一些改变。

只有一个级别会有一个子菜单-有可能一些1级项目不会有任何子菜单-所以我正在寻找一个可以呈现0或1子菜单的模式。

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

代码语言:javascript
复制
<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();
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-13 23:03:22

将菜单创建为带有StringBuilder的字符串会容易得多。但是如果你真的想要递归控件,你可以克隆控件,并在每个菜单级别上重复使用它。我在这个演示中使用了Repeater,因为它更适合重复项目。因此,首先我们创建一个类和一些演示数据

代码语言:javascript
复制
public class MenuItem
{
    public string name { get; set; }
    public List<MenuItem> menuitems { get; set; }
}

用虚拟数据填充它

代码语言:javascript
复制
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();
}

将Repeater控件添加到页面。也有一个PlaceHolder,这样它就可以保存自己的副本。

代码语言:javascript
复制
<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>

现在在ItemDataBound事件中,我们克隆Repeater1,用子菜单填充它,将它添加到父Repeater的PlaceHolder中,并附加一个ItemDataBound程序调用,这样Repeater就可以生成它自己的子节点。

代码语言:javascript
复制
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);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51822834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档