欢迎光临
我们一直在努力

《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换-.NET教程,Asp.Net开发

建站超值云服务器,限时71元/月

在visual studio中开发web项目,web 窗体页由两部分组成:视觉元素(html、服务器控件和静态文本)和该页的编程逻辑。 一般将这两个组成部分分别存储在一个单独的文件中。可视元素在一个 .aspx 文件中创建,而代码位于一个单独的类文件中(.aspx.vb 或 .aspx.cs)。或者有时候也会在同一文件中创建视觉元素和代码。

而在asp.net forums的web窗体页中没有找到我们熟悉的.aspx.cs文件,也没有发现任何c#代码,取而代之是一个个控件,代码在哪里?!

下面将以login.aspx为例详细说明asp.net forums是如何实现代码分离和换皮肤的:

首先我们看看login.aspx在两种皮肤样式下的运行效果

(theme:default)(theme:electricmidnight)

只是更改了一下asp.net forums的默认皮肤,同样是login.aspx,显示的是两种不同的皮肤样式。先回想一下vs.net中,先不论换皮肤功能,如果我们要实现一个登陆页面,那么我们在aspx或ascx页中将输入帐号密码的textbox、登陆的button拖入,在编辑区双击button,写上对button点击事件处理的代码,多么方便,大部分代码都由vs.net为我们完成了。

我们再来看login.aspx的源码:

<%@ import namespace="aspnetforums.components" %>

<%@ register tagprefix="forums" namespace="aspnetforums.controls" assembly="aspnetforums.controls" %>

<%@ register tagprefix="mp" namespace="metabuilders.webcontrols.masterpages" assembly="metabuilders.webcontrols.masterpages" %>

<mp:contentcontainer runat="server" id="mpcontainer" masterpagefile="~/themes/masterpage.ascx">

<mp:content id="maincontent" runat="server">

<p align="center">

<forums:navigationmenu displaytitle="true" id="navigationmenu1" runat="server" />

<br />

<br />

<br />

<forums:login runat="server" id="postview1" />

</p>

</mp:content>

</mp:contentcontainer>

注:其中 <mp:***> ,这个是一个第三方控件,其目的是为了保证界面的一致性,提取页面间的重复代码。

从源码中我们没有看到任何构成login.aspx页面效果的textbox、button等基本元素。甚至没有发现一行c#代码,不过如果您对页面控件比较熟悉不难发现原来asp.net forums中将登陆的界面封装为了控件(在此对页面控件并不作专门介绍,如果您对控件相关知识还比较陌生的话,强烈推荐您查阅相关资料或书籍)。 原来登陆界面的实现就是在<forums:login runat="server" id="postview1" />控件中,从

<%@ register tagprefix="forums" namespace="aspnetforums.controls" assembly="aspnetforums.controls" %>

我们可以知道login控件对应的类应该为:aspnetforums.controls.login,在vs.net中,切换到类视图,找到aspnetforums.controls.login并转到对应文件:

(该图告诉您如何快速的查找控件对应的文件)

 

从代码中看到的该控件是从skinnedforumwebcontrol类继承的:

public class login : skinnedforumwebcontrol {  // 从 skinnedforumwebcontrol 基类继承

……

}

我们还是先看看基类skinnedforumwebcontrol。

using system;

using system.drawing;

using system.collections;

using system.collections.specialized;

using system.web;

using system.web.ui;

using system.web.ui.webcontrols;

using aspnetforums;

using aspnetforums.components;

using system.componentmodel;

using system.io;

using system.web.security;

using aspnetforums.enumerations;

namespace aspnetforums.controls {

[

parsechildren(true)

]

/// <summary>

/// 几乎asp.net forums中所有控件的基类,继承自webcontrol,并实现inamingcontainer接口

/// </summary>

public abstract class skinnedforumwebcontrol : webcontrol, inamingcontainer {

forumcontext forumcontext = forumcontext.current;

string skinfilename = null;

string skinname = null;

string returnurl = null;

forummode mode = forummode.user;

public skinnedforumwebcontrol() {

// 使用的皮肤——如果是匿名用户,则使用系统默认样式

//

if (forumcontext.user.isanonymous) {

skinname = globals.skin;

}

else {

skinname = forumcontext.user.theme;

}

}

/// <summary>

/// 当开发复合服务器控件或模板服务器控件时,必须重写此方法。

/// 通知使用基于合成的实现的服务器控件创建它们包含的任何子控件,以便为回发或呈现做准备。

/// </summary>

protected override void createchildcontrols() {

control skin;

// 装载用户控件

skin = loadskin();

// 初始化控件

initializeskin(skin);

controls.add(skin);

}

/// <summary>

/// 通过skinname和skinfilename找出用户控件文件的路径,装载该用户控件后的control对象

/// </summary>

/// <returns></returns>

protected control loadskin() {

control skin;

// 用户控件文件所在位置

string skinpath = globals.getskinpath() + "/skins/" + skinfilename.trimstart(/);

string defaultskinpath = globals.applicationpath + "/themes/default/skins/" + skinfilename.trimstart(/);

// 必须要有skinfilename属性

if (skinfilename == null)

throw new exception("you must specify a skin.");

// 从用户控件文件获取 usercontrol 对象。

try {

skin = page.loadcontrol(skinpath);

}

catch (filenotfoundexception) {

// 如果没有找到指定皮肤的用户控件文件,装载默认皮肤下的控件文件

try {

skin = page.loadcontrol(defaultskinpath);

}

catch (filenotfoundexception) {

throw new exception("critical error: the skinfile " + skinpath + " could not be found. the skin must exist for this control to render.");

}

}

return skin;

}

/// <summary>

/// 初始化控件,并绑定控件数据

/// </summary>

/// <param name="skin"></param>

protected abstract void initializeskin(control skin);

/// <summary>

/// 用户控件文件(*.ascx)路径

/// </summary>

public string skinfilename {

get {

return skinfilename;

}

set {

skinfilename = value;

}

}

/// <summary>

/// 皮肤名

/// </summary>

protected string skinname {

get {

return skinname;

}

set {

skinname = value;

}

}

public forummode mode {

get { return mode; }

set { mode = value; }

}

}

}

 

从代码中可以看出,基类skinnedforumwebcontrol继承自webcontrol类并实现了inamingcontainer接口。既然是自定义控件,自然就是从webcontrol类继承。之所以实现inamingcontainer接口,是因为在开发模板化控件时,应实现该接口以避免同一页上的命名冲突。

在skinnedforumwebcontrol中有两个重要的属性:skinname 和 skinfilename,分别表示皮肤名和用户控件文件路径。在asp.net forums2.0中,在web目录下有一个themes目录,每种皮肤对应一个目录,例如default、electricmidnight,每个皮肤文件夹下有三个文件夹:image、skins和style,分别用来存放该皮肤下对应的图片文件、用户控件文件(*.ascx)和样式表css文件。通过这两个属性,我们可以知道用户控件文件(*.ascx)的真实路径,例如我们的skinname是default,skinfilename是skin-login.ascx,那么用户控件的路径是themes/default/skins/skin-login.ascx,同理,如果我们将皮肤样式换成electricmidnight,那么用户控件的路径将是 themes/electricmidnight/skins/skin-login.ascx。

还有两个重要的方法,一个是loadskin(),在该方法中,首先根据上面介绍的两个属性找出用户控件文件的路径,然后通过page.loadcontrol(defaultskinpath)方法,从用户控件文件中获取 usercontrol 对象。这也就是为什么皮肤不同,页面样式就不同,因为随着皮肤的不同,我们load的用户控件文件也不同,我们只要将用户控件文件样式设置的不一样,就可以随着皮肤的不同显示的样式也不一样。

 

但是光这些还不够,我们还需要识别ascx页中的页面控件。例如在skin-login.ascx中,我们必须知道哪个输入框是帐号的,那个输入框是密码的,知道用户是否点击了登陆按钮。回想vs.net中,ide自动帮我们把这些控件根据id识别出来,在ide中双击按钮,就可以直接加上响应点击事件的代码,多么方便。但是现在我们该如何?……

基类中还有一个抽象的initializeskin(control skin)方法,所有继承自skinnedforumwebcontrol的控件都必须override该方法,因为我们可以在这个方法中来初始化控件,在loadskin()方法中我们已经通过page.loadcontrol(defaultskinpath)方法返回了一个usercontrol,现在我们在initializeskin(control skin)中通过control.findcontrol 方法,在usercontrol中搜索指定的服务器控件,并对控件进行绑定数据和事件。还是以login控件为例,摘取aspnetforums.controls.login类中的部分代码如下:

public class login : skinnedforumwebcontrol {  // 从 skinnedforumwebcontrol 基类继承

string skinfilename = "skin-login.ascx"; // 默认皮肤文件

textbox username; // 帐号输入框

textbox password; // 密码输入框

button loginbutton; // 登陆按钮

}

public login() : base() {

if (skinfilename == null)

skinfilename = skinfilename; // 定义默认的皮肤文件

}

// 重写 initializeskin 初始化

override protected void initializeskin(control skin) {

// 查找ascx页中id是username的textbox控件

username = (textbox) skin.findcontrol("username");

// 查找ascx页中id是password的textbox控件

password = (textbox) skin.findcontrol("password");

// 找到登陆按钮

loginbutton = (button) skin.findcontrol("loginbutton");

loginbutton.click += new system.eventhandler(loginbutton_click); // 绑定登陆按钮的click事件

loginbutton.text = resourcemanager.getstring("loginsmall_button");

}

在skin-login.ascx中,我们的每个控件都有一个id,例如用户名输入框的id是username,这样,我们就可以在重写initializeskin(control skin)的时候,利用username = (textbox) skin.findcontrol("username");这样的方法来一个个找到对应用户控件文件中的控件。并可以对绑定数据和事件,例如:loginbutton.click += new system.eventhandler(loginbutton_click),绑定登陆按钮的click事件。

综上所述,asp.net forums就是通过自定义控件来实现代码分离的,并通过在控件中动态装载用户控件文件(*.aspx)来实现换皮肤功能的。当您在看asp.net forums2.0源代码的时候,再也不要被<forums:navigationmenu displaytitle="true" id="navigationmenu1" runat="server" />这样的代码所吓倒,直接切换到类视图,找到对应的类:aspnetforums.controls.navigationmenu,从类代码中……

如果您还不是很理解,您可以自己研读一下asp.net forums2.0的源码,如果您觉得太复杂,请看模拟asp.net forums实现可以换皮肤的控件一文的例子,也许有助您理解:)

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换-.NET教程,Asp.Net开发
分享到: 更多 (0)