Click here to Skip to main content
15,883,940 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi,

I am creating a website where I would like some neat context menu controls. I have already found some handy code to create the menu (but post 'em if you've got 'em) but I'm looking to create a standard UC for the site. I was hoping to be able to add items to the control in the same way that an HTML select does or even the asp:dropdown does (more likely the latter as the HTML will be produced from the code in the same way).

Is this even possible?
HTML
<uc:ContextMenu id="CustomControl">
   <uc:MenuLink Value="blah" Text="blah" Url="\blah" />
   <uc:MenuButton  Value="blah" Text="blah"  önClick="Blah_OnClick" />
</uc:ContextMenu>

And how is it done?
Maybe it's the same as design time attributes in winform user controls?

PS: I haven't really started looking at control attributes yet so please post any useful info on adding these to the control

Thanks in advance ^_^
Posted

So What i understood is that you need your user control to have the attributes that you can set from aspx markup.

If you define public properties in your user control then use can use it like attributes from you pages' asp.net markup.

Tell me If my understanding is not correct.
 
Share this answer
 
Comments
Andy Lanng 14-May-12 6:29am    
Thanks for your prompt reply ^_^
I do need to have attributes that I can set from aspx markup, so thank you for that.

I also need to be able to add controls (or even just htmlcontrols) to a list of controls as in the code above.

Is that as simple as including public methods with specific names i.e.
private List _menuItems = new List();
public void Add(HtmlControl item)
{
(item!=null)
_menuItems.Add(item);
}
Once I've cracked this then I can even create my own Item class if I need to, but that's looking too far ahead.

My ambition is to have a control that can be used from the markup language, as well as in c#, just as if it was a standard control. Thanks again ^_^
You need to add the following to your enclosing class:

C#
[ParseChildren(false)]
[PersistChildren(true)]
public partial class ContextMenu : UserControl
{...}


That will allow you to add items between the opening and closing tags of your UserControl. I have also included those tags on my ContextMenuitem class so that I can add infinite nested submenus

Another overload you may want to use is

C#
protected override void AddedControl(Control control, int index)
{
  try
  {
    ContextMenuItem cmitem = ((ContextMenuItem)control);

    if (_subItems == null)
      _subItems = new List<contextmenuitem>();

    List<contextmenuitem> newlist = new List<contextmenuitem>();

    newlist.AddRange(_subItems.AsQueryable().Take(index).ToList());
    newlist.Add(cmitem);
    newlist.AddRange(_subItems.AsQueryable().TakeWhile((item, i) => i >= index));

    _subItems = newlist;
  }
  catch (InvalidCastException ice)
  {
    //This is an expected error more several controls which should not be parsed here anyway
  }
}
</contextmenuitem></contextmenuitem></contextmenuitem>


You could perform a check for several different class types or use inheritance, so long as each control has the same properties.

I personally used one item class, overloaded the RenderControl so that it did nothing and wrote the markup in a new RenderHtml that I called from the ContectMenu class' Render control. That way you don't need to worry about the HtmlControl RenderControl being called. Just write it yourself:

C#
public override void RenderControl(HtmlTextWriter writer){}
public void Renderhtml(HtmlTextWriter writer, string previousId, int iteration = 0)
{
  writer.WriteFullBeginTag("li");

  string currentId = previousId + "_" + iteration.ToString();

  if (this.ViewState["ControlStyle"] != null)
  {

    Control_Style style = (Control_Style)Enum.Parse(typeof(Control_Style), this.ViewState["ControlStyle"].ToString());

    string closeTag = string.Empty;

    switch (style)
    {
      case Control_Style.Button:
        writer.WriteBeginTag("button");
        closeTag = "</button>";
        break;
      case Control_Style.Hyperlink:
        writer.WriteBeginTag("a");
        closeTag = "";
        break;
      case Control_Style.SubMenu:
        writer.WriteBeginTag("span");
        closeTag = "";
        break;
    }

    foreach (object key in this.ViewState.Keys)
    {
      if (this.ViewState[key.ToString()] != null && this.ViewState[key.ToString()].ToString().Length > 0)
      writer.WriteAttribute(key.ToString(), this.ViewState[key.ToString()].ToString());
    }
    writer.Write(">");
    writer.WriteLine(this.Text);
    writer.WriteLine(closeTag);

    if (_subItems != null && _subItems.Count > 0)
    {
      writer.WriteBeginTag("div");
      writer.WriteAttribute("id", currentId);
      writer.Write(">");

      writer.WriteFullBeginTag("ul");
      foreach (ContextMenuItem cmi in _subItems)
      {
        cmi.Renderhtml(writer, currentId);
      }
      writer.WriteEndTag("ul");
      writer.WriteEndTag("div");
    }
  }
  else
    throw new HttpUnhandledException("Menu Items must be either a HtmlControls or a Sub Menu!");

  writer.WriteEndTag("li");

}


This is prolly overkill but I have also made sure that my submenu divs have distinctive IDs so that I can make the javascript work over each one. I still haven't got that bit working yet but I'll post it if anyone needs it when I'm done :D
 
Share this answer
 
Comments
Andy Lanng 16-May-12 6:20am    
thanks you for your very detailed answer.

I need to get my head around this a bit but I will post any future question I might have

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900