今天看了一下asp.net Forums,来说说它的皮肤控件。
首先说说它的皮肤控件基类:SkinnedForumWebControl,这个类位于AspNetForums.Controls命名空间下。
代码
#region VSS
/*
* $Header: /HiForums/Controls/BaseClasses/SkinnedForumWebControl.cs 1 05-10-26 15:04 Jacky $
*
* $History: SkinnedForumWebControl.cs $
*
* ***************** Version 1 *****************
* User: Jacky Date: 05-10-26 Time: 15:04
* Created in $/HiForums/Controls/BaseClasses
*
* ***************** Version 1 *****************
* User: Jacky Date: 05-10-21 Time: 14:20
* Created in $/HiForums/Controls/BaseClasses
*
* ***************** Version 3 *****************
* User: Jacky Date: 05-09-20 Time: 19:15
* Updated in $/ASP.NET Forums/Controls/BaseClasses
*/
#endregion
using System;
using System.IO;
using System.Web.UI;
using AspNetForums.Components;
using AspNetForums.Enumerations;
namespace AspNetForums.Controls
{
[
ParseChildren(true)
]
/// <summary>
/// 皮肤控件基类
/// </summary>
public abstract class SkinnedForumWebControl : Control, INamingContainer
{
#region 成员字段
private ForumContext forumContext = ForumContext.Current;
private string skinFilename = null;
private string skinName = null;
// string returnURL = null;
private ITemplate inlineSkin = null;
private ForumMode mode = ForumMode.User;
#endregion
#region 构造函数
// *********************************************************************
// SkinnedForumWebControl
//
/// <summary>
/// Constructor
/// </summary>
// ***********************************************************************/
public SkinnedForumWebControl()
{
// What skin should be used?
//
if (forumContext.User.IsAnonymous)
{
skinName = Globals.Skin;
}
else
{
skinName = forumContext.User.Theme;
}
}
#endregion
#region 子控件创建
// *********************************************************************
// CreateChildControls
//
/// <summary>
/// This event handler adds the children controls.
/// </summary>
// ***********************************************************************/
protected override void CreateChildControls()
{
Control skin = null;
if (inlineSkin != null)
{
inlineSkin.InstantiateIn(this);
InitializeSkin(this);
}
else
{
// Load the skin
skin = LoadSkin();
// Initialize the skin
InitializeSkin(skin);
Controls.Add(skin);
}
}
#endregion
#region 调用皮肤
// *********************************************************************
// LoadControlSkin
//
/// <summary>
/// Loads the names control template from disk.
/// </summary>
// ***********************************************************************/
protected Control LoadSkin()
{
Control skin;
string skinPath = Globals.GetSkinPath() + "/Skins/" + SkinFilename.TrimStart('/');
string defaultSkinPath = Globals.ApplicationPath + "/Themes/default/Skins/" + SkinFilename.TrimStart('/');
// Do we have a skin?
if (SkinFilename == null)
throw new Exception("You must specify a skin.");
// Attempt to load the control. If this fails, we're done
try
{
skin = Page.LoadControl(skinPath);
}
catch (FileNotFoundException)
{
// Ok we couldn't find the skin, let's attempt to load the default skin instead
try
{
skin = Page.LoadControl(defaultSkinPath);
}
catch (FileNotFoundException)
{
throw new Exception("错误:皮肤文件 " + skinPath + " 没有找到. 皮肤必须被指定,以用于控件的呈现.");
}
}
return skin;
}
#endregion
#region 皮肤初始化(抽像类)
// *********************************************************************
// InitializeSkin
//
/// <summary>
/// Initialize the control template and populate the control with values
/// </summary>
// ***********************************************************************/
protected abstract void InitializeSkin(Control skin);
#endregion
#region 公有属性:皮肤文件名
// *********************************************************************
// SkinName
//
/// <summary>
/// Allows the default control template to be overridden
/// </summary>
// ***********************************************************************/
public string SkinFilename
{
get { return skinFilename; }
set { skinFilename = value; }
}
#endregion
#region 皮肤名
// *********************************************************************
// SkinName
//
/// <summary>
/// Used to construct paths to images, etc. within controls.
/// </summary>
///
// ********************************************************************/
protected string SkinName
{
get { return skinName; }
set { skinName = value; }
}
#endregion
#region 公有属性:皮肤
public ITemplate Skin
{
get { return inlineSkin; }
set { inlineSkin = value; }
}
#endregion
#region 公有属性:论坛模式
public ForumMode Mode
{
get { return mode; }
set { mode = value; }
}
#endregion
}
}
它继承于Control, INamingContainer,Control是所有控件的基类,而INamingContainer按口标识在 System.Web.UI.Page 对象的控件层次结构内创建新 ID 命名空间的容器控件,也就是说实现了此接口,它能够帮你完成父子控件的命名工作,实现如下效果:“tr1_td1_control1”。
SkinnedForumWebControl基类的主要工作是重写了基类的CreateChildControls方法。
代码
protected override void CreateChildControls()
{
Control skin = null;
if (inlineSkin != null)
{
inlineSkin.InstantiateIn(this);
InitializeSkin(this);
}
else
{
// Load the skin
skin = LoadSkin();
// Initialize the skin
InitializeSkin(skin);
Controls.Add(skin);
}
}
当内部皮肤控件不为空时,加载内部皮肤控件。
注:这个内部皮肤控件是一个ITemplate(模板接口)里面可以放任意服务器端控件。
不然,由LoadSkin()方法加载经子类指定了用户控件名称的皮肤控件初始化后添加到Controls中。
InitializeSkin()是一个abstract方法,由子类来实现数据绑定,注册事件等行为。
LoadSkin方法如下:
代码
protected Control LoadSkin()
{
Control skin;
string skinPath = Globals.GetSkinPath() + "/Skins/" + SkinFilename.TrimStart('/');
string defaultSkinPath = Globals.ApplicationPath + "/Themes/default/Skins/" + SkinFilename.TrimStart('/');
// Do we have a skin?
if (SkinFilename == null)
throw new Exception("You must specify a skin.");
// Attempt to load the control. If this fails, we're done
try
{
skin = Page.LoadControl(skinPath);
}
catch (FileNotFoundException)
{
// Ok we couldn't find the skin, let's attempt to load the default skin instead
try
{
skin = Page.LoadControl(defaultSkinPath);
}
catch (FileNotFoundException)
{
throw new Exception("错误:皮肤文件 " + skinPath + " 没有找到. 皮肤必须被指定,以用于控件的呈现.");
}
}
return skin;
}
基类完成后,我们要做的就是实现各种皮肤的用户控件和子类控件。然后在网页上通过ContentContainer控件来调用。
这就是Asp.Net Forums的换肤原理,欢迎各位达人指正。