Question

I am trying to make a user controls for multi-level menu. I have created first-level control which works. Its iterating with repeater and instantiating my own MenuButton class. Each MenuButton object has children of same type.

The question is: How to create MenuButton control inside MenuButton.aspx file?

I am using repeater like this

<%@ Control ClassName="MenuButton" Language="C#" AutoEventWireup="true" CodeBehind="MenuButton.ascx.cs"
    Inherits="MenuSolution._12.TEMPLATE.CONTROLTEMPLATES.MenuButton, MenuSolution, Version=1.0.0.0, Culture=neutral, PublicKeyToken=284eb573cd58385d" %>
<%@ Register TagPrefix="a" Namespace="MenuSolution._12.TEMPLATE.CONTROLTEMPLATES"
    Assembly="MenuSolution, Version=1.0.0.0, Culture=neutral, PublicKeyToken=284eb573cd58385d" %>
<li runat="server">
    <% if (Children.Count == 0)
       { %>
            <a href="<%# Url %>"><%# Description %></a>
    <% }
       else
       {
    %>
    <a href="<%# Url %>" class="dropdown-toggle" data-toggle="dropdown">
        <%# Description %><b class="caret"></b></a>
    <ul class="dropdown-menu multi-level">
        <asp:Repeater ID="repDynamicRows" runat="server">
            <ItemTemplate>
                <a:MenuButton runat="server" id="button" url='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
                    children='<%# DataBinder.Eval(Container.DataItem, "ChildItems") %>' description='<%# DataBinder.Eval(Container.DataItem, "Description") %>' />
            </ItemTemplate>
        </asp:Repeater>
    </ul>
    <%
       }
    %>
</li>

and this code does not place MenuButton code inside final HTML. I was trying to register this control like:

<%@ Register TagPrefix="a" TagName="MenuButton" Src="~/_controltemplates/MenuButton.ascx" %>

But this leads to circural reference.

How should i do that?

Was it helpful?

Solution

You need to Load the control from code instead of the markup. That is due to how the asp.net compiler creates the assemblies from your mark up.

I made the following changes to load the control from the codebehind. I had to change the databinding as well by changing the # to = (and have properties on the control).

Control MenuButton.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MenuButton.ascx.cs" Inherits="WebApplication1.MenuButton" %>
<li id="Li1" runat="server">
    <% if (Children.Count == 0)
       { %>
            <a href="<%= Url %>"><%= Description %></a>
    <% }
       else
       {
    %>
    <a href="<%= Url %>" class="dropdown-toggle" data-toggle="dropdown">
        <%= Description %><b class="caret"></b></a>
    <!-- is now a server control -->
    <ul class="dropdown-menu multi-level" runat="server" ID="ul1">
       <!-- the page_load adds MenuButtons here -->       
    </ul>

    <%
       }
    %>
</li>

Codebehind MenuButton.ascx.cs

public partial class MenuButton : System.Web.UI.UserControl
{
    public String Url { get; set; }
    public string Description { get; set; }
    public List<MenuItem> Children { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (Children != null)
        {
            foreach (var menuItem in Children)
            {
                // Create a button from the ascx file
                var but = (MenuButton)LoadControl("/MenuItems/MenuButton.ascx");
                // bind!
                but.Children = menuItem.Children;
                but.Description = menuItem.Description;
                but.Url = menuItem.Url;

                if (ul1 != null)
                {
                    // add our button
                    ul1.Controls.Add(but);
                }
            }
        }
    }
}

ViewModel

 public class MenuItem
 {
     public List<MenuItem> Children { get; set; }
     public String Url { get; set; }
     public string Description { get; set; }
 }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top