Themes first introduced in VS.NET 2005. As we all know a theme is a collection of property settings that allow you to define the look of pages and controls. Themes can define the look of a specific Web application across all of its pages, or across all Web applications on a server.
Themes are made up of a set of elements: skins, cascading style sheets (CSS), images, and other resources. At a minimum, a theme will contain skins. Themes are defined in special directories in your Web site or on your Web server.
Let’s say that I’m working in a project that as a requirement the web application must have 3 themes available. The easiest way to do it is to include the images folder into each of the theme folders. That is because every css file and skin that references to an image will just have to look for in the current folder(the current theme’s folder) for the images subfolder.
For example:
.Header
{
background-image: url(images/topbackground.png); background-repeat: repeat-x; width: 100%;
margin: 0px;
}
Images folder is a subfolder to the current theme’s folder. So now is so much easier to create a new theme. All I have to do is to create another folder to store the new theme’s elements into the themes folder.What about the images that have nothing to do with skins and css files? These images should be included into the images subfolder that exists into each of the theme folders. So again the only thing I’ll have to do is to use this code:
protected void Page_Init(object sender, EventArgs e)
{
this.imgDelete.Src = "~/App_Themes/" + Page.Theme + "/images/delete.png"; this.imgInsert.Src = "~/App_Themes/" + Page.Theme + "/images/add.png";
}
So now no matter which theme the page is using the images will always be shown correctly.
Keep coding!!!
For my first post I chose to present my approach on localization.
My approach is very similar with the explicit way the .NET uses to handles localized resource file. Let’s say we have a website that has an amount of n web forms and we want to localize it in n languages. I think that it’s not that easy to maintain because each web form will be linked with n resource files. .NET provides the capability to use global resources that are not linked with a specific web form for example:
<asp:Label ID="lblwelcome"runat="server" Text="<%$ Resources:resource, welcome%>"> </asp:Label>
But what if you want to use the resource files for a variety of different projects that belong to the same solution? Let’s have a view of the approach I propose.
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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 runat="server">
<title>Untitled Page</title>
</head><body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="!!Label1!!"></asp:Label><br />
<asp:Label ID="Label2" runat="server" Text="!!Label2!!"></asp:Label><br />
<asp:Label ID="Label3" runat="server" Text="!!Label3!!"></asp:Label><br />
<asp:Label ID="Label4" runat="server" Text="!!Label4!!"></asp:Label><br />
<asp:TextBox ID="TextBox1" runat="server" Text="!!Textbox1!!"></asp:TextBox>
</div>
</form></body></html>
So far the only thing that is a bit odd is the value of the Text property of the controls. Hmm, let’s have a look on the Localizer class and things might become a bit clearer.
Localizer.cs
using System;
using System.Resources;
using System.Globalization;
using System.Configuration;
namespace Localization{
/// <summary>
/// Localization utility class
/// </summary>
public class Localizer
{
private ResourceManager _applicationResourceManager;
private CultureInfo _uiCulture;
public Localizer()
{
_uiCulture = new CultureInfo("en-US");
_applicationResourceManager = new ResourceManager .Localizer.Messages", this.GetType).Assembly);
string[] mfs = this.GetType().Assembly.GetManifestResourceNames();
}
public CultureInfo UICulture
{
get { return _uiCulture;}
set { _uiCulture = value;}
}
public string GetString(string key,CultureInfo culture,params string[] parameters)
{
string msgTemplate = _applicationResourceManager.GetString(key,culture);
return string.Format(msgTemplate,parameters);
}
public string GetString(string key,params string[] parameters)
{
if (parameters == null || parameters.Length==0)
{
string msg = _applicationResourceManager.GetString(key,_uiCulture);
if (msg == null)
{
return "$" + key;
}
return msg;
}
else
{
string msgTemplate = _applicationResourceManager.GetString(key,_uiCulture);
if (msgTemplate == null)
{
return "$" + key;
}
return string.Format(msgTemplate,parameters);
}
}
}}
What this class simply does is to retrieve the value from any of the localized resources depending on a given key and all that by simply call the method GetString. Well ok some might think but there is nothing new about that. So far we’ve just seen a class that can be used by all the different projects in a solution if it comes for localization. The best part is in the next snippet of code by which without writing a single line of code we can localize any control in a web form.
Default.aspx.cs
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Globalization;
public partial class _Default : System.Web.UI.Page {
protected override void Render(HtmlTextWriter writer)
{
Localization.Localizer localizer = new Localization.Localizer();
//localizer.UICulture = new CultureInfo("el-GR");
StringBuilder sb = new StringBuilder();
HtmlTextWriter newWriter = new HtmlTextWriter(new StringWriter(sb));
base.Render(newWriter);
string html = sb.ToString();
MatchCollection col = Regex.Matches(html, @"!!*(.*?)!!");
foreach (Match match in col)
{
html = Regex.Replace(html, match.ToString(), localizer.GetString(match.ToString().Replace("!!", "")));
}
writer.Write(html);
}
}
All the processing is being made by the Render method. In order for this approach to be reusable and maintainable the Render method should be included in a BasePage class and all web forms in the site should inherit from that. I hope you 'll find this as useful as I did.
Download
Happy coding :)