思想
项目中页面由一个容器和若干复合控件组成。
1.容器
容器用来容纳界面中的复合控件。容器也有类似于页面模版的作用。所有包含容器的页面都使用模版文件所定义的页面样式。在1.1种asp.net还没有专门的,forums是使用的第三方组件。在2.0中asp.net已经有了自己的容器MasterPage。两者的功能和使用方式差不多。
2.复合控件
每个复合控件由一个.cs文件(Controls项目中)和一个.ascx文件(web项目中)。web项目下的Themes文件夹放置的是不同风格的界面复合控件的.ascx文件。一种风格用一个文件存放。Themes下面的Default文件夹就是存放默认风格的.ascx文件。
这样做的主要目的是为了将使逻辑部分和界面分离开。只需要增加新风格的.ascx文件就可以实现增加新的界面样式。逻辑部分就可以实现复用。
页面直接使用Controls中创建的复合控件实现界面的加载。
实现
1.创建界面的基类Controls.kinnedForumWebControl
1.1继承Control, INamingContainer
如果自定义服务器控件类继承自Control类,那么必须在控件类之前设置元数据属性ParseChildren和PersistChildren。
[ParseChildren(true),PersistChildren(false)]
如上代码所示,在控件类前设置了两个元数据属性ParseChildren和PersistChildren。前者用于告知页面分析器把控件标记中的内容解析为属性还是子控件,该属性值设置为true,则表示解析为属性。后者用于告知设计器把控件标记中的内容保存为属性还是子控件,该属性值设置为false,表示保存为属性。
如果自定义控件类继承自WebControl类,那么就不需要以上的元数据属性设置,因为,WebControl类已经应用了这些元数据属性了。
2.1属性
以后将要加载的自定义控件模版的文件名
string skinFilename = null;
风格的名称
string skinName = null;
返回的url地址
string returnURL = null;
定义用子控件填充模板化 ASP.NET 服务器控件的行为。子控件表示页上定义的内联模板。
ITemplate inlineSkin = null;
关于ITemplate请参考
http://msdn2.microsoft.com/zh-cn/library/system.web.ui.itemplate(VS.80).aspx
http://msdn2.microsoft.com/zh-cn/library/system.web.ui.itemplate_members(VS.80).aspx
3.1方法
protected override void CreateChildControls()
{
Control skin = null;
if (inlineSkin != null)
{
//ITemplate.InstantiateIn方法
//当由类实现时,定义子控件和模板所属的 Control 对象。然后在内联模板中定义这些子控件。
inlineSkin.InstantiateIn(this);
//该方法为虚方法,由子类实现。用来初始化界面。
InitializeSkin(this);
}
else
{
// 从模版文件中加载界面
skin = LoadSkin();
//当由类实现时,定义子控件和模板所属的 Control 对象。然后在内联模板中定义这些子控件。
InitializeSkin(skin);
//将界面添加到this.Controls中
Controls.Add(skin);
}
}
//加载模版文件方法
protected Control LoadSkin()
{
Control skin;
string skinPath = Globals.GetSkinPath() + "/Skins/" + SkinFilename.TrimStart('/');
string defaultSkinPath = Globals.ApplicationPath + "/Themes/default/Skins/" + SkinFilename.TrimStart('/');
// 是否有界面文件?
if (SkinFilename == null)
throw new Exception("You must specify a skin.");
// 加载控件模版
try
{
skin = Page.LoadControl(skinPath);
}
catch (FileNotFoundException)
{
// 出错时加载默认风格的界面控件模版
try
{
skin = Page.LoadControl(defaultSkinPath);
}
catch (FileNotFoundException)
{
throw new Exception("" + skinPath + "");
}
}
return skin;
}
2.界面的子类
以Controls.login为例
[ParseChildren(true)]
public class Login : SkinnedForumWebControl
{
.
//界面模版文件
string skinFilename = "Skin-Login.ascx";
//界面模版中的控件
TextBox username;
TextBox password;
Button loginButton;
DropDownList autoLogin;
.
public Login() : base()
{
// 负给默认的模版文件名
if (SkinFilename == null)
SkinFilename = skinFilename;
}
//重写base.eateChildControls方法
protected override void CreateChildControls()
{
base.CreateChildControls();
}
// 重写base.InitializeSkin方法
override protected void InitializeSkin(Control skin)
{
//找到模版中对应的控件,并添加事件。
username = (TextBox) skin.FindControl("username");
password = (TextBox) skin.FindControl("password");
loginButton = (Button) skin.FindControl("loginButton");
loginButton.Click += new System.EventHandler(LoginButton_Click);
loginButton.Text = ResourceManager.GetString("LoginSmall_Button");
autoLogin = (DropDownList) skin.FindControl("autoLogin");
if ( autoLogin.Items.FindByValue("30") != null)
autoLogin.Items.FindByValue("30" ).Selected = true;
}
}
3.aspx页面中使用复合控件相关:
<%@ Register TagPrefix="Forums" Namespace="AspNetForums.Controls" Assembly="AspNetForums.Controls" %>
<%@ Import Namespace="AspNetForums.Components" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<Forums:Login id="Login1" runat="server"></Forums:Login>
</asp:Content>
复合控件参考
http://search.microsoft.com/results.aspx?q=INamingContainer&l=1&mkt=zh-CN&FORM=QBMH1
http://msdn2.microsoft.com/zh-cn/library/system.web.ui.inamingcontainer(VS.80).aspx
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpref/html/frlrfsystemwebuiitemplateclasstopic.asp
http://www.microsoft.com/china/msdn/library/webservices/asp.net/ASPNETContDev.mspx?mfr=true