views:

133

answers:

2

Hello all.

I am building a pop-out menu, and the client wants it to be able to pop out continously based on a heirarchy.

For example, the first pane is a list of options. When they are hovered over, another pane should pop up next to it with the next level of options, and so on until the last level of options is reached.

I can handle all the javascript and stuff, but I can't think of a way to continously embed repeaters inside repeaters. I know I could do it once by putting a repeater inside another, but then I would only have two layers.

I need to be able to continously embed repeaters for each layer of options, or achieve this with a similar technique using a different control.

Any help is great, thanks!

A: 

You won't be able to build this in mark up. You'll have to add the controls dynamically in your code behind by building the Repeater for each level and adding it to the previous Repeater's template. It will require a full postback for each option selected because the nested Repeater could potentially be of different depth depending on which option is chosen.

You might be better off doing this all client-side, though, using AJAX and javascript. When an option is chosen, fire off an AJAX request to see if that option has sub-options. If it does (return them), then dynamically build the new options control using javascript and add it to the page. When a different option is chosen, you'll remove the elements from the DOM holding the previously chosen options sub-options.

tvanfosson
Thanks, that's helpful :)
A: 

If you can get your menu out in form of a list of MenuItem objects, each of which has a (sometimes empty) list of sub items (and I really mean a List<MenuItem> here... we're going to use this collection as a datasource for a sub-repeater, so it needs to implement IEnumerable<T>) as a property MenuItem.SubItems, you could probably make use of a UserControl that loops out one menu level, and calls upon itself for the next.

In the UserControl you'd have something like this:

<li><a href='<%= this.MenuItem.Url %>'><%= this.MenuItem.LinkText %></a></li>
<asp:Repeater ID="UCRepeater" runat="server">
    <HeaderTemplate>
        <ul>
    <ItemTemplate>
        <menu:MenuItem ID="MenuItemUC" runat="server" />
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>

The UserControl in the ItemTemplate is the same one, so for each item template the same thing will be rendered.

Below is the Code Behind for this user control, and this is where the magic happens:

public partial class MenuItemUserControl : UserControl
{
    // A property we'll use as the data source
    public MenuItem MenuItem { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        // If the current menu item has sub items, we bind the repeater to them
        // And by the way, there is no use doing this on every postback. First 
        // page load is good enough...
        if(!Page.IsPostBack) {
        {
            if(MenuItem.SubItems.Count > 0)
            {
                UCRepeater.DataSource = MenuItem.SubItems;
                UCRepeater.DataBind();
            }
        }
    }
    protected void UCRepeater_OnItemDataBound(object sender, 
                RepeaterDataBoundEventArgs e)
    {
        // Every time an Item is bound to the repeater, we take the current
        // item which will be contained in e.DataItem, and set it as the 
        // MenuItem on the UserControl

        // We only want to do this for the <ItemTemplate> and
        // <AlternatingItemTemplate>
        if(e.Item.ItemType == ListItemType.Item || 
            e.Item.ItemType == ListItemType.AlternatingItem)
        {
            var uc = (MenuItemUserControl)e.Item.FindControl("MenuItemUC");
            if(uc != null)
            {
                // This is the magic. Abrakadabra!
                uc.MenuItem = (MenuItem)e.DataItem;
            }
        }

    }
}

So in order to get this to work, the only thing missing is really a nice way of getting your data out as a hierarchical list of MenuItems. This I'll leave to your data access layer (and it would be cheap easy using LINQ to SQL or Entity Framework... ;) )

DISCLAIMER: This code is provided as is, and I wrote it off the top of my head. I have not tested it, but I think it will work - and if it doesn't, it could at least give you an idea of how to solve the problem. If you have problems, please post them in comments and I'll try to help out - but there are no promises of success here. Just a willingness to help out! =)

Tomas Lycken