页面与后台代码分离的方式之CS模式

添加人:iyond七级(4375分)   添加时间:2007-05-21    阅读次数:2089  收藏此教程

对于平时用惯了VS IDE的人来说,如果看到cs的源码,可能一下子就懵了,没有我们所熟悉的.aspx.cs后台代码文件,甚至是在页面里面也根本没有熟悉的HTML标记.取而代之的是一个个的控件标签. 我们先看看首页代码:

<%@ Page SmartNavigation="False" Language="C#" enableViewState = "false" %>
<%@ Register TagPrefix="CS" Namespace="CommunityServer.Controls" Assembly="CommunityServer.Controls" %>
<%@ Register TagPrefix="CSD" Namespace="CommunityServer.Discussions.Controls" Assembly="CommunityServer.Discussions" %>
<%@ Import Namespace="CommunityServer.Galleries.Components" %>
<%@ Import Namespace="CommunityServer.Blogs.Components" %>
<%@ Import Namespace="CommunityServer.Components" %>
<%@ Register TagPrefix="CSH" Namespace="CommunityServer.Controls.HomePage" assembly="Openlab.CSAddOns" %>
< CS:SelectedNavigation Selected="home" runat="Server"/>
<CS:ContentContainer runat="server" id="MPContainer">
    <CS:Content id="BodyContentRegion" runat="server">
        <CSH:BodyLayoutTemplate runat="server"/>
    </CS:Content>
</CS:ContentContainer>

     
整个页面全部由控件定义而成,没有后台代码文件asp.cs,我们只有通过类视图来查看,通过页面上的声明,很容易可以找到这些控件的实现代码.比如: BodyLayoutTemplate控件,根据前缀和上面的声明,可以知道该控件是 CommunityServer.Controls.HomePage.BodyLayoutTemplate类.我们再跟进去看这个类里到底写了些什么.(我们现在先不管那个ContentContainer标记,那个是Metabuilder开发的一个控制页面风格统一的自定义控件)

public class BodyLayoutTemplate : TemplatedWebControl
{
    // Methods
    public BodyLayoutTemplate()
    {
        this._bodyLayout = null;
    }
    protected override void AttachChildControls()
    {
        this._bodyLayout = this.FindControl("bodylayout") as PlaceHolder;
    }
    // Fields
    private PlaceHolder _bodyLayout;
}

进去才发现这个类本身几乎没有做什么事情. 就定义了一个容器控件,用来增加其他子控件. 再跟到它的父类TemplatedWebControl里去.

public abstract class TemplatedWebControl : WebControl, INamingContainer ...

原来它是个模板控件.这让我想起在首页里显示的blog列表,论坛文章列表等都是放在这个里面的.我们知道一般模板控件都要override CreateChildControls() 这个方法,那么加载的信息一定在这里了.果然,我们看看这段代码
protected override void CreateChildControls()
{
    Controls.Clear();

    // 1) A custom theme setting is the most important
    Boolean _skinLoaded = false;
    if (!Globals.IsNullorEmpty(ThemeName))
    {
        if (SkinFolderExists)
        {
            if (SkinFileExists && this.Page != null)
            {
                Control skin = this.Page.LoadControl(this.SkinPath);
                this.Controls.Add(skin);
                _skinLoaded = true;
            }
        }
    }

    // 2) Next, look for an inline template
    if (!_skinLoaded && SkinTemplate != null)
    {
        SkinTemplate.InstantiateIn(this);
        _skinLoaded = true;
    }

    // 3) last resort is the default external skin
    if (!_skinLoaded && this.Page != null && this.DefaultSkinFileExists)
    {
        Control defaultSkin = this.Page.LoadControl(this.DefaultSkinPath);
        this.Controls.Add(defaultSkin);
        _skinLoaded = true;
    }
    //locations were successful, throw.
    if (!_skinLoaded)
    {
        throw new CSException(CommunityServer.Components.CSExceptionType.SkinNotFound);
    }
    // 4) If none of the skin

    AttachChildControls();
}

这里就可以清晰的看到到底是怎么一回事了,开始是加载自定义的theme,但由于不存在那个路径,所有,程序就执行了第三步,加载默认的theme,
protected virtual string DefaultSkinPath
{
    get
    {
        return "~/Themes/default/Skins/" + ExternalSkinFileName;
    }
}
protected virtual String ExternalSkinFileName
{
    get
    {
        if (SkinName == null)
            return CreateExternalSkinFileName(null);

        return SkinName;
    }
    set
    {
        SkinName = value;
    }
}
protected virtual string CreateExternalSkinFileName(string path)
{
    return CreateExternalSkinFileName(path, "Skin-" + this.GetType().Name);
}

这下可以全部看清了,原来页面是加载了位于 themes/default/skins/目录下的 skin-Skin-BodyLayoutTemplate.ascx控件. 赶紧到这个目录下去看,果然找到了这个文件:
<%@ Control Language="C#" %>
<%@ Register TagPrefix="CS" Namespace="CommunityServer.Controls" Assembly="CommunityServer.Controls" %>
<%@ Register TagPrefix="Galleries" Namespace="CommunityServer.Galleries.Controls" Assembly="CommunityServer.Galleries" %>
<%@ import Namespace="CommunityServer.Components" %>
<%@ Register TagPrefix="CSH" Namespace="CommunityServer.Controls.HomePage" assembly="Openlab.CSAddOns" %>
<div id="HomePageColumn2">
    <ul>
     <li><Galleries:AggregatePortalPictureListing Count="3" ShowPictures="true" SortBy="ThreadDate" runat="server" /></li>
     <li><CSH:BlogRoll Count="8" TitleLength="7" runat="server" ShowRssLink="true"/><br /></li>
     <li><CS:WhoIsOnline runat="server" /></li>
    </ul>
</div>
<div id="HomePageColumn1">
    <ul>
        <li><%= CSContext.Current.SiteSettings.HomePageContent %></li>
        <li><CSH:LatestForumPosts Count="8" TitleLength="24" ShowTitleOnly="true" runat="server" /></li>
        <li><CSH:LatestBlogPosts Count="8" TitleLength="24" ShowTitleOnly="true" runat="server"/></li>
    </ul>
</div>

 
至此,眼前的路豁然开朗起来, 这里的 latestBlogPosts,LatestForumPosts不就是我们首页里的博客列表论坛列表吗. 同样,这里也是使用控件来定义. 现在我们在根据以上的跟踪思路,就可以很轻松的知道我应该怎么去修改这个论坛了. 好,再下面的跟踪就不用再说了. 我们回到正题.
可以看出,整个cs的页面都是以这种方式来设计和实现的. 我们可以总结成一句话: 前台页面所有元素均定义成自定义控件,把实现代码抽取成单独的程序集. 当然, 这个自定义控件一般使用模板控件来控制页面结构,使用具体的元素控件来表现内容. 这样架构我个人认为至少有以下几个好处:
1.页面与后台逻辑几乎完全分离,所有的功能,即使是一个很小的页面元素也使用控件实现,这样,我们可以很容易的实现软件的换肤功能, 所作的只不过是在新的皮肤里将这些元素重新组合一下而已.
2.层级结构清晰. 我们可以看到cs已经将页面总多的控件分了层次来逐级加载.最上层是控制页面结构的空白模板控件,内部一级一级的分别加载.这样使得真个页面的控件耦合度较低. 我们可以按照自己的方式将不同的元素控件组合到某个框架里去.
3.可扩展性强. 比如这次我需要将博客中的文章列表也在首页显示出来,那么,我只需要在上面的页面里自己再定义一个控件,然后在CommunityServer.Controls.HomePage名字空间下再写出这个控件的实现方法即可.不影响现有的任何其他模块代码.
不过这种方式是有性能上的损失的,还好,整个系统都使用了cache, 可以弥补这里的损失.
以后,在我们开发个性化要求很强的软件里, 比如一些较为时尚的站点和应用程序,需要换肤功能, CS提供了一种不错的参考思想
1页 第1上一页1下一页
相关的教程: Community Server
收藏此教程

当前平均分: 0.0(0 次打分)

-5-4-3-2-1012345
评论主题
您的大名
您的评论
验证码 点击换一个验证码
知识库搜索: