My musings about .NET and what not

Fixing ASP.NET Server Control Rendering Issues with Tag Mapping

Extraneous attributes. Default styles. Stray markup. Sometimes, ASP.NET server controls just don't render the way you want them to. Even in those cases where Microsoft is just trying to be "helpful", sometimes I just want them to get out of the way and let me do my thing. Here, I'll demonstrate a quick-and-dirty way to get rid of that extra markup, using the tag as an example.

I was greeted this morning by this blog post from my friend Anthony Grace over at CodersBarn.com. In it, Anthony writes:

Recently, I have been experiencing some difficulty applying CSS correctly to some of the OOTB (out-of-the-box) ASP.NET controls. Earlier today, I was trying to apply a CSS image border using the ASP.NET image control, but couldn't get it to render correctly. In the end, I had to use a regular HTML img tag.

Ouch. It seems he's been bitten by the ASP.NET Image Border Style Bug um, Feature. And if you've ever tried to apply border styles via CSS to the server control, perhaps you've been bitten too.

How ASP.NET Renders the Image Server Control

You see, when you place an Image server control on a page, like this:

<asp:Image ID="Image1" runat="server" ImageUrl="~/Images/girl.jpg" />

Figure 1

It renders onto the page as follows:


            

See that inline style="border-width:0px;" attribute in the img tag? We didn't put that there, Microsoft did. I suspect they do this to get rid of the ugly default border that is applied by most browsers to image hyperlinks. I don't really know. All I know is this a big P.I.T.A. when you're trying to style the tag via CSS, as you can see from the following example:

<%@ Page Language="C#" %>
 
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Image Bordertitle>
   <style type="text/css">
      .imageStyle {
         padding: 6px;
         background-color: #CCCCCC;
         border: 2px solid #0099CC;
      }
   style>
head>
<body>
   <form id="form1">
      <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/girl.jpg"
         CssClass="imageStyle" />
   form>
body>
html>

Figure 2

The page above results in the following source output:


   Image Border
   


   

Which, when rendered onto the page, looks like this:

Figure 3

You can see back in Figure 2, we've defined our .imageStyle class and properly specified it via the CssClass property of the Image tag. The background color and padding render fine. So, where did our pretty blue border go? If you understand the cascade part of CSS, you know that the inline style="border-width:0px;" attribute added by the default rendering overrides any border styles we set from the page level, or from an external CSS stylesheet.

The Solution

There are actually several workarounds for this. You can override the style in the page's OnPreRender event. You can set the border width on all Image tags at the control level by setting the BorderWidth property (though this pretty much defeats the advantages of using CSS). And of course, you can use a regular HTML tag, which is what Anthony did.

Or, you can forget about using a "workaround" and fix the real problem. You can do that by deriving a new class from System.Web.UI.WebControls.Image and applying it automatically to all tags in your site via an often-overlooked feature called tag mapping.

First, create a new class (I'm calling this one ImageBorderless) that derives from Image:

using System.Web.UI.WebControls;
 
public class ImageBorderless : Image
{
   public override Unit BorderWidth
   {
      get { return base.BorderWidth.IsEmpty ? Unit.Pixel(0) : base.BorderWidth; }
      set { base.BorderWidth = value; }
   }
}

Figure 4

Then, in your web.config file, in the section of , add a tag mapping as follows:

<pages>
   <tagMapping>
      <add tagType="System.Web.UI.WebControls.Image" mappedTagType="ImageBorderless" />
   tagMapping>
pages>

Figure 5

This tag mapping simply maps all instances of the Image tag to the ImageBorderless type.

Rerun the page, and you'll see that pesky style attribute is now gone, and that the page renders correctly.


   Image Border
   


   

 

Figure 6

Conclusion

As handy as ASP.NET server controls are (most of the time), sometimes anomalous rendering issues make it tricky to have them look or behave the way we want. When that happens, you can always derive a new control, override properties and behaviors as needed, and map that wayward tag to your derived type via tag mapping.

Have fun!

Subscribe to this blog for more cool content like this!

kick it on DotNetKicks.com

shout it on DotNetShoutOut.com

vote it on WebDevVote.com

Bookmark / Share

    » Similar Posts

    1. Nested ListViews and More - Working with Databound Controls Inside the ListView
    2. Master / Detail Editing With a ListView and DetailsView
    3. Resetting the Page Index in a ListView

    » Trackbacks & Pingbacks

    1. You've been kicked (a good thing) - Trackback from DotNetKicks.com

      Fixing ASP.NET Server Control Rendering Issues with Tag Mapping — February 16, 2009 2:48 PM
    2. Thank you for submitting this cool story - Trackback from DotNetShoutout

      Fixing ASP.NET Server Control Rendering Issues with Tag Mapping : LeeDumond.com — February 16, 2009 3:40 PM
    Trackback link for this post:
    http://leedumond.com/trackback.ashx?id=43

    » Comments

    1. Anthony Grace avatar

      Really interesting solution Lee. I wasn't familiar with tag mapping. Some of the other controls cause problems also if my memory serves me right. I think I will create a library of customized controls for future use and use tag mapping to apply them. This has been really helpful, thanks!

      Anthony :-)

      Anthony Grace — February 16, 2009 4:01 PM
    2. Scott avatar

      An interesting approach, but it is much easier to just use the '!Important' declaration to override the image element's inline style:

      border: 2px solid #0099CC !Important;

      - Scott

      Scott — February 16, 2009 4:05 PM
    3. Lee Dumond avatar

      @Anthony: Thanks much! I didn't mention it in the post, but the ImageButton control exhibits this same behavior, so you might want to keep that in mind.

      @Scott: Yes, I've applied the !important declaration to these issues in the past, but again, that's just a workaround. The actual point of this post was to demonstrate *in general* how to override default behavior with a custom type, and how to apply tag mapping using that type. I only used Anthony's issue as a convenient example.

      Lee Dumond — February 16, 2009 4:17 PM
    4. Cohen avatar

      It actually saved my day, tonight :)

      Had somethin I couldn't fix with a control and this saved me a whole lot of "search - replace"-action

      Cohen — February 18, 2009 3:35 PM
    5. Lee Dumond avatar

      @Cohen - Reading comments like yours makes this all worthwhile. Thanks man.

      Lee Dumond — February 18, 2009 5:02 PM
    6. Clay McKinney avatar

      Screaming like a little girl. I am so happy. Thank you.

      Clay McKinney — September 18, 2009 10:44 PM
    7. Bhangu avatar

      Good solution, but i think the solution provided by Scott in comments section is the right and easiest way to do this.

      Cheers

      Bhangu — December 17, 2009 7:25 AM

    » Leave a Comment