A replacement of ASP.NET 2.0 theme&skin

.NET 2.0应该已经进入代码封装阶段了,不太可能有太大的变化了。ASP.NET 2.0 里提供的Theme/Skin解决方案,一方面过于繁复,而且有潜在的问题(具体参考另一篇Post: ASP.NET 2.0 Theme 的一个问题)。

一直在想一个简单稳定的替代方案,中秋节休息在家,想到了以下东东。

Theme/Skin大体可以分成三部分,布局、文字(包括字体和配色)和图片(包括动画)。

布局由Master页控制,可以继续用,网上已经有很多文章讨论如何动态改变Master页的办法。

文字和图片由网页中的一个属性Skin控制。不同的Skin存放在不同的目录结构中。

需要目录结构:
/Style  默认的Stylesheet目录
/Style/Skin1 对应与Skin1的Stylesheet目录
/Style/Skin2 对应与Skin2的Stylesheet目录
……

/Image  默认的图片目录
/Image/Skin1 对应与Skin1的图片目录
/Image/Skin2 对应与Skin2的图片目录
……


简单的步骤如下:

1、派生一个Page class,加入自己的属性 Skin,让所有的网页继承自这个Page class。

2、处理网页的Stylesheet,在Page class加入以下代码(根据Skin改写对应的Stylesheet文件的位置):

protected override void OnLoad(EventArgs e)
{
 
base.OnLoad(e);
 
if (this.Skin.Length > 0)
 
{
  
foreach (Control c in ((Control)this.Header).Controls)
  
{
   
if (typeof(HtmlLink).IsInstanceOfType(c))
   
{
    HtmlLink hc 
= (HtmlLink)c;
    
if (hc.TagName.ToLower() == "link")
    
{
     hc.Href 
= hc.Href.Substring(0, hc.Href.LastIndexOf("/"+ 1+ this.Skin + "/" + hc.Href.Substring(hc.Href.LastIndexOf("/"+ 1);
    }

   }

  }

 }

}


这样你的Stylesheet文件就可以自动根据指定的Skin变化了。

(如果需要的话,可以用同样的方法在WebControl级别再设一个Skin,这样你的WebControl(ascx)也可以有不同与Page的Skin,这种情况应该比较少,将有可能导致页面风格的不一致。)

3、处理图片,派生一个System.Web.UI.WebControls.Image class,加入如下代码(同上,改写Image对应的位置):

protected override void  OnLoad(EventArgs e)
{
 
base.OnLoad(e);
 System.Web.UI.Control c 
= this.NamingContainer;
 
while (c != null)
 
{
  
if (typeof(Skined.Page).IsInstanceOfType(c))
  
{
   Skined.Page bp 
= (Skined.Page)c;
   
if (bp.Skin.Length > 0)
   
{
    
this.ImageUrl = this.ImageUrl.Substring(0this.ImageUrl.LastIndexOf("/"+ 1+ bp.Skin + "/" + this.ImageUrl.Substring(this.ImageUrl.LastIndexOf("/"+ 1);
    
break;
   }

  }

  c 
= c.NamingContainer;
 }

}


同理,你的图片页会随着Skin自动转换了。

(其他Image对象的处理方法相同,比如ImageButton)


使用它们:

在设计网页的时候,可以完全抛开Skin部分,使用默认的目录中的Stylesheet和图片,例如:

在你的网页或者Master页里,使用:<link type="text/css" rel="stylesheet" href="Style/Default.css" />
如果你的网页指定了Skin1:
protected void Page_Load(object sender, EventArgs e)
{
 this.Skin = "Test";
 ... ...
Render到客户端的将是:<link type="text/css" rel="stylesheet" href="Style/Skin1/Default.css" />
如果没有指定,将仍然Render出:<link type="text/css" rel="stylesheet" href="Style/Default.css" />


图片的使用:
<%@ Register TagPrefix="Skined" Namespace="Skined" %>
<Skined:Image ImageUrl="~/Image/calendar.gif" runat="server" />
同样的,如果你的网页指定了Skin1,Render到客户端的将是:<img src="Image/Skin1/calendar.gif">


几点说明:

1、这里只是一个构思和初步的代码,所有的代码都是未经优化的,如果直接使用的话,请自行处理,比如异常。
2、转载请注明出处
3、欢迎讨论
4、因为在国外有一段时间了,很多词汇不知道国内的翻法,只好直接用E文,上次自己乱翻,这次不敢了。

posted @ 2005-09-19 02:28 dawave 阅读(...) 评论(...) 编辑 收藏