SyntaxHighlighter

Wednesday, September 10, 2008

Apply themes to Images in Asp.Net

The Asp.Net Themes approach is somewhat lacking when it comes to images. It is easy enough to switch between CSS and Skin files, but switching between images aren't as trivial. Luckily there is a relatively simple way to do this.

My thinking was to set the image folder dynamically. First, we'll have to figure out what our image path is. Say one use the following structure for your image folders:

App_Themes/Theme1/Images
App_Themes/Theme2/Images
...

The following ImagePath accessor can be used to determine the current theme's image path (I would recommend you to put this in a Base class for this to be accessible to all pages/controls):
public string ImagePath
{
get
{
return string.Format("{0}://{1}{2}/App_Themes/{3}", Request.Url.Scheme, Request.Url.Authority, Request.ApplicationPath, Page.Theme);
}
}

Now that we know where the currently selected theme's images are, we need to set the path for the controls in the aspx page. This is easy enough if you using normal HTML controls as follows:
<img src='<% Response.Write(ImagePath); %>/Image.jpg' />

But this approach does not work for server controls. If you use the following line, you'll receive an error:

<asp:Image ImageUrl="<% Response.Write(ImagePath); %>/Image.jpg" runat="server" />

Error:
Server tags cannot contain <% ... %> constructs.

One could set the asp:image's ImageUrl in the codebehind, but I find it to be a bit clunky. In order to use the ImagePath in the aspx file, one can use an approach by Dave Reed.

Create a class in the App_Code called CodeExpressionBuilder:
using System;
using System.CodeDom;
using System.Web.Compilation;
using System.Web.UI;

[ExpressionPrefix("Code")]
class CodeExpressionBuilder : ExpressionBuilder
{
public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
{
return expression;
}

public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return new CodeSnippetExpression(parsedData.ToString());
}
}


One can now set the ImageUrl in the aspx file as follows:
<asp:Image ImageUrl='<%$ Code: ImagePath + "/Image.jpg" %>' runat="server" />

2 comments:

Eli said...

This is exactly what I'm looking for, but I don't understand where and how to declare ImagePath, can I use there a property of the Profile ? (which is like a Global variable)?

Unknown said...

ImagePath can simply be a property (accessor) in your codebehind file.

(Typically one would use a base class for all codebehind files, so it is a good practice to put it in the base class, so it is accessible to all codebehind files.)