Friday 4 July 2008

Control Adapters

Had my first run it with ASP.Net control adapters this week. I was using the built in Menu control which was unfortunately rendering as a table. I needed a menu that rendered as a list using <li> tags instead.

Up to the plate stepped control adapters. These let you mess with the presentation layer of the control, in this case change a menu from rendering <Table> tags to <li>.

Here's how...

Add a App_Browsers folder to the project, you can do this from the right click menu.
Add in a "Form.browser" file. This is an XML file that tells the ASP system what class to use instead of the menus presentation layer. Here's a sample.

<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Menu" adapterType="TDWeb.MenuControlAdapter" />
</controlAdapters>
</browser>
</browsers>

The "TDWeb.MenuControlAdapter" is the Namespace and class name.


namespace TDWeb {

#region Namespace references

using System;
using System.Web.UI;
using System.Web.UI.Adapters;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.Adapters;


#endregion

public class MenuControlAdapter : MenuAdapter {

#region Methods

private bool MenuItemContainsSelectedItem(MenuItem menuItem) {

if ( menuItem.Selected )
return true;

foreach ( MenuItem childItem in menuItem.ChildItems ) {

if ( this.MenuItemContainsSelectedItem(childItem) ) {
return true;
}

}

return false;

}

protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);

if ( this.Control != null ) {

this.SelectCurrentPage(this.Control.Items);

}

}

protected override void RenderContents(HtmlTextWriter writer) {

if ( this.Control != null ) {

writer.AddAttribute(HtmlTextWriterAttribute.Id,"qm0");
writer.AddAttribute(HtmlTextWriterAttribute.Class,"qmmc");
writer.RenderBeginTag(HtmlTextWriterTag.Ul);
foreach ( MenuItem menuItem in this.Control.Items ) {
this.RenderMenuItem(menuItem, writer, 0, true);
}
writer.RenderEndTag();

}

}

private bool RenderMenuItem(MenuItem menuItem, HtmlTextWriter writer, int level, bool withArrows) {

bool selected = this.MenuItemContainsSelectedItem(menuItem);

if ( this.Control.StaticDisplayLevels >= level ) {

// Render each item as a
  • ...

  • //writer.RenderBeginTag(HtmlTextWriterTag.Li);
    writer.Write(@" if (menuItem.Selected)
    {
    writer.Write(@" class=""selectedmenuitem"" ");
    //writer.AddAttribute(HtmlTextWriterAttribute.Class, "selectedmenuitem");
    }
    writer.Write(@">");
    // Current item should be styled with "selected" class ...
    //if ( selected )
    // writer.AddAttribute(HtmlTextWriterAttribute.Class, @"qmparent");

    // If a description was specified, add it as a tooltip ("title" attribute) ...
    if ( menuItem.ToolTip != string.Empty )
    writer.AddAttribute(HtmlTextWriterAttribute.Title, menuItem.ToolTip);


    // Render the "href" attribute ...
    //if ( !menuItem.Selected )
    writer.AddAttribute(HtmlTextWriterAttribute.Href, menuItem.NavigateUrl);


    //writer.AddAttribute(HtmlTextWriterAttribute.Class, "selectedmenuitem");

    //// Render the "A" element ...
    //if (level == 0)
    //{
    // writer.AddAttribute(HtmlTextWriterAttribute.Class, "qmparent");
    //}
    writer.RenderBeginTag(HtmlTextWriterTag.A);
    writer.WriteEncodedText(menuItem.Text);
    writer.RenderEndTag();



    //if ( withArrows )
    // writer.WriteEncodedText(@" | ");

    // Now render any child items ...
    if ( this.Control.StaticDisplayLevels > level ) {
    if (menuItem.ChildItems.Count > 0 ) {
    writer.RenderBeginTag(HtmlTextWriterTag.Ul);
    foreach ( MenuItem childItem in menuItem.ChildItems ) {
    this.RenderMenuItem(childItem, writer, level + 1, false);
    }
    writer.RenderEndTag();
    }
    }

    // Close the
  • ...
  • tag ...
    writer.Write(@"");
    //writer.RenderEndTag();
    }

    return menuItem.Selected;

    }

    private void SelectCurrentPage(MenuItemCollection menuItems) {

    Uri rawUrl = new Uri(this.Control.Page.Request.Url, this.Control.Page.Request.RawUrl);
    this.SelectCurrentPage(menuItems, rawUrl);

    }

    private void SelectCurrentPage(MenuItemCollection menuItems, Uri rawUrl) {

    foreach ( MenuItem menuItem in menuItems ) {

    string navigateUrl = this.Control.ResolveUrl(menuItem.NavigateUrl);
    Uri targetUrl = new Uri(rawUrl, navigateUrl);
    menuItem.Selected = string.IsNullOrEmpty(menuItem.NavigateUrl = rawUrl.MakeRelativeUri(targetUrl).ToString());

    this.SelectCurrentPage(menuItem.ChildItems, rawUrl);

    }

    }

    #endregion

    }

    }