Ritengo i temi di ASP.NET 2.0 una funzionalità veramente utile. Purtroppo però, fin dai primi sviluppi, mi sono scontrato con la limitazione di non poter caricare le immagini in base al tema corrente (senza usare gli skin).
Durante i primi sviluppi mi ero documentato e avevo visto che gli ExpressionBuilder erano customizzabili, quindi era possibile creare un ExpressionBuilder che si occupava di ritornare il path di un'immagine (o di un file qualsiasi) salvato all'interno della cartella del tema corrente. In pratica mi consentiva di fare questo:
<asp:Image ID="imgMessaggio" runat="server" ImageUrl="<%$ Theme: Images/Message.gif %>" />
<img id="imgMessaggioHtml" runat="server" src="<%$ Theme: Images/Message.gif %>" border="0" />
Per poter sfruttare questa funzionalità nei miei progetti ho creato una class library con due classi. La prima si occupa della gestione dei path (ThemeResourceManager) mentre la seconda (ThemeExpressionBuilder) è l'implementazione dell'expression builder vero e proprio.
ThemeResourceManger
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
namespace rossimarko.Web
{
///
/// Classe per la gestione delle risorse contenute nei temi
///
public class ThemeResourceManager
{
///
/// Ritorna il percorso virtuale completo di un file contenuto all'interno del tema corrente
///
public static string GetResourceVirtualPath(string VirtualPath)
{
HttpContext context = HttpContext.Current;
Page currentPage = null;
//Riferimento alla pagina
if (context.Handler != null)
currentPage = context.Handler as Page;
//Se non esiste ricerca la pagina nel previous handler
if (currentPage == null && context.PreviousHandler != null)
currentPage = context.PreviousHandler as Page;
if (currentPage != null)
//Ritorna il percorso
return GetResourceVirtualPath(currentPage.Theme, VirtualPath);
else
return VirtualPath;
}
///
/// Ritorna il percorso di un file contenuto all'interno di un tema
///
public static string GetResourceVirtualPath(string ThemeName, string VirtualPath)
{
return string.Format("~/App_Themes/{0}/{1}", ThemeName, VirtualPath);
}
///
/// Ritorna il percorso fisico di un file contenuto nella cartella del tema corrente
///
public static string GetResourcePhysicalPath(string VirtualPath)
{
return HttpContext.Current.Server.MapPath(GetResourceVirtualPath(VirtualPath));
}
///
/// Ritorna il percorso fisico di un file contenuto nella cartella di un tema
///
public static string GetResourcePhysicalPath(string ThemeName, string VirtualPath)
{
return HttpContext.Current.Server.MapPath(GetResourceVirtualPath(ThemeName, VirtualPath));
}
}
}
ThemeExpressionBuilder
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
namespace rossimarko.Web
{
public class ThemeExpressionBuilder : System.Web.Compilation.ExpressionBuilder
{
public override bool SupportsEvaluate
{
get
{
return true;
}
}
public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
{
//Riferimento al type
CodeTypeReferenceExpression target = new CodeTypeReferenceExpression(typeof(ThemeResourceManager));
//Riferimento alla chiave
CodeExpression keyExpression = new CodePrimitiveExpression(entry.Expression);
//Riferimento al metodo
CodeMethodReferenceExpression methodReference = new CodeMethodReferenceExpression(target, "GetResourceVirtualPath");
//Invocazione del metodo
CodeMethodInvokeExpression method = new CodeMethodInvokeExpression(methodReference, keyExpression);
return method;
}
}
}
Per poter utilizzare il ThemeExpressionBuilder sarà sufficiente modificare la configurazione del web.config:
<compilation debug="true" strict="true" explicit="true">
<expressionBuilders>
<add expressionPrefix="Theme" type="rossimarko.Web.ThemeExpressionBuilder"/>
<expressionBuilders>
<compilation>
Questo ovviamente presuppone che abbiate aggiunto nel vostro progetto la reference alla dll creata.