ASP.NET Controls– Applying CSS styles to a Menu control

This is subject to which I ended up returning from time to time, either for professional purposes, for some pet project or simply to help a friend.

For those of you that already played with Menu control knows that applying CSS styles to the standard ASP.NET Menu control can be a real frustrating task. For all the other I hope that this post avoid or at least reduce this pain.

Problem

The main question regarding styles is how the control renders. The Menu control renders HTML element TABLE, TR and TD and this approach bring us two main problems:

  • Turns CSS style configuration more complex
  • Increases the overall HTML size

I’m not sure why the control renders like this but I believe is related to multi browser CSS compatibility. We must not forget that even today we face several multi browser CSS problems (with IE8 the differences went minimal but we still have to deal with older browsers for many years) and by the time NetFX 2.0 saw the daylight the gap between browsers were larger and rendering HTML elements TABLE, TR and TD was the one that offered less compatibility issues.

Solution

Fortunately, ASP.NET 2.0 added the concept of ControlAdapter. This is a piece that can be associated to a control type and enable us to change the way that control renders.

As you can imagine, this opened a door to adjust controls without changing the control itself. But, there’s always a but, those kind of associations Adapter/Control are (out of the box) an application setting.

The mapping is made with a Browser Definition File Schema that should look similar to:

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

These files should be deployed to the App_Browsers folder.

Now that we know about the ControlAdapters is clear that we need one to the Menu control. Since I’m a lazy programmer, I won’t create from scratch a MenuAdapter. Instead I will use an existing one.

You can find in CodePlex a project that give us a set of Adapters very useful in most common scenarios: ASP.NET 2.0 CSS Friendly Control Adapters.

Between those adapters there’s a specific one for the Menu control. This adapter renders the Menu control as an unordered list using Div, Ul e Li HTML elements and this way allow us to easily apply CSS styles without loosing multi browser compatibility and with less Html signature. Here is an Html sample:

<div class="AspNet-Menu-Horizontal">
    <ul class="AspNet-Menu">
        <li class="AspNet-Menu-WithChildren  AspNet-Menu-Selected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0')" class="AspNet-Menu-Link  AspNet-Menu-Selected">
Test 0</a>
            <ul>
                <li class="AspNet-Menu-WithChildren  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 1')"  class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 1</a>
                    <ul>
                        <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 1\Test 1a')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 1a</a>
 </li>
                        <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 1\Test 1b')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 1b</a>
 </li>
                        <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 1\Test 1c')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 1c</a>
 </li>
                    </ul>
                </li>
                <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 2')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 2</a>
 </li>
                <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 3')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 3</a>
 </li>
                <li class="AspNet-Menu-Leaf  AspNet-Menu-ParentSelected">
<a href="javascript:__doPostBack('ctl00$B$fvMenu','bTest 0\Test 4')" class="AspNet-Menu-Link  AspNet-Menu-ParentSelected">
Test 4</a>
 </li>
            </ul>
        </li>
    </ul>
</div>

A great sample is available here and the source code can be downloaded here.

ASP.NET Controls – Validators problem (NetFx 1.1 versus NetFx 2.0 or higher)

It is not a secret that I have a passion related to ASP.NET Controls ID and all related subjects.

This time I’ll write about a problem I found while migrating a NetFx 1.1 application to a new server.

The problem is about Validators and how they render the data needed to validate Client-Side.

Scenario NetFX 1.1.4

All data is rendered thru attributes and this way they must only follow the attributes naming conventions.

Scenario NetFX 2.0 or higher

Most required data is rendered thru Expando attributes. This means that an javascript object is created to host the required data.

At first look this seems quite the same, only with a different storage  approach, but it hides one tricky issue related to naming convention differences between Html attributes and Javascript variables.

The tricky issue

I believe that most of us tries to follow the best patterns and naming conventions and if we all did this on old applications this wouldn’t be a problem.

While migrating an old .Text v0.91 application to a new server, without NetFX 1.1 installed, I found that all pages with Validators raise a javascript error.

Digging into it I found the error in this line:

var ctl00_pageBody-2_RequiredFieldValidator1 = document.all ? document.all["ctl00_pageBody-2_RequiredFieldValidator1"] : document.getElementById("ctl00_pageBody-2_RequiredFieldValidator1");

The problem is obvious, the character ‘-‘ is a javascript operator and cannot be used in a variable name . The javascript parser after finding the ‘-‘ say that an ‘;’ is expected after ‘ctl00_pageBody’.

So … Why this didn’t occurred in the old server? What lead us to this point?

As I noticed before, in NetFX 1.1 this object didn’t exist, all data were simple rendered as attributes.

I didn’t find any good reason for naming a control like this but in fact this is a absolutely valid control ID.

Solutions

There are two approaches, we can either force the validator to render attributes or change the ID value to remove unwanted characters.

The first is obviously the better one but as you will see is a global application change.

Instruct the validator to render attributes

The validator controls are ready to work in a legacy mode, but to enable that mode we need to change the all behavior of our application. We can do that adding the following web.config data:

<system.web>
    <xhtmlConformance mode="Legacy"/>

While this solution is the one I like the most I choose to use the other simply because I don’t know exactly the potential side-effects, and I need to made a chirurgical change minimizing impacts.

Change the controls ID

This approach requires you to change all controls ID in the validators hierarchy to prevent javascript naming problems. It could take some time but, usually, it should present no problems.

That is not my case. It took me some time to find where the pageBody-2 control.

I ended up finding that it was an UserControl, loaded dynamically and its ID was also composed dynamically. Unfortunately, this was all done in a private method belonging to an internal base class and the only practical solution was to override the Page Render method and replace the pattern ‘_pageBody-‘ with ‘_pageBody_’.

I know it is a dirty solution … I don’t like it … but this is a short term solution before migrating the application to CommunityServer.

Mental note

Never use the ‘-‘ to name your controls ID property. Try the ‘_’ or any other without special meaning in Javascript.