DotText阅读笔记--换肤的实现

DotText的换肤实现起来挺复杂的,阅读了代码后把这块的心得记录下来.

1.先简单说哈结构,(详细的结构描述可以看"DotText源码阅读(6) --模版皮肤  ")
其实就是一些用户控件.这里主要有个用户控件叫"PageTemplate.ascx"这个相当于是整套模版的Index.
每套模版放在一个文件夹内(比如winxpBlue),"PageTemplate.ascx"和css这些在这个文件夹的根目录,然后用户控件组在这个文件夹下的Controls里面 ,注意,用户控件的后台代码不是
跟ascx放在一起的,而是在网站根目录的UI\Controls下,也就是说各套模版共用同样的cs.

2.再来说哈主要相关的页面和类.
主要类就是Dottext.Web.UI.WebControls.MasterPage,这个类是整个换肤的主类,是个容器,是最关键的.它用来装载用户控件,具体操作下面再说
另外一个类就是ContentRegion,这个类是个Panel下继承来的,主要用来装在"内容"的用户控件

其实DotText在处理页面布局时,已经划分了好了,就是一个Head,一个Foot,一个LeftColumn(工具箱),还有一个"内容"(这个用来装载内容的,比如装载详细信息,信息列表之类的,而上面提到的ContentRegion就是用来装载这个的)

现在看default.aspx的设置
<%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="false" Inherits="Dottext.Web.UI.Pages.DottextMasterPage"%>
<%@ Register TagPrefix="DT" Namespace="Dottext.Web.UI.WebControls" Assembly="Dottext.Web" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
 <HEAD>
  <title><asp:Literal ID="pageTitle" Runat="server" /></title>
  <meta content=".Text" name="GENERATOR">
  <link id="MainStyle" type="text/css" rel="stylesheet" runat="Server"/>
  <link id="SecondaryCss" type="text/css" rel="stylesheet" runat="Server"/>
  <link id="RSSLink" title="RSS" type="application/rss+xml" rel="alternate" runat="Server"/>
 </HEAD>
 <body>
  <form id="Form1" method="post" runat="server">
   <DT:MASTERPAGE id="MPContainer" runat="server">
    <DT:contentregion id="MPMain" runat="server">
     <asp:PlaceHolder id="CenterBodyControl" runat="server"></asp:PlaceHolder>
    </DT:contentregion>
   </DT:MASTERPAGE></form>
 </body>
</HTML>

这里default的后台Dottext.Web.UI.Pages.DottextMasterPage,一会我们再说这个干了什么.
现在注意页面,一个MasterPage控件,里面包含了一个id为MPMain的ContentRegion的Panel,在Panel上有一个PlaceHolder.

3,现在来说到底是怎么工作的
在说明怎样工作之前,要看哈DotText的UrlReWriting(详细的可以看"dotText源码阅读(5)--URLreWrite和Handler ").DotText是用HttpHandle来实现UrlReWriting的 .
注意:其实用户访问的每一个页面都是转向到default.aspx,而之所以显示不同的内容是因为模版上的ID为"MPMain"的ContentRegion装载了不同的用户控件而已.
我们看哈WebConfig上关于Handle的Config上的设置
<HandlerConfiguration defaultPageLocation="default.aspx" type="Dottext.Common.UrlManager.HandlerConfiguration, Dottext.Common">
  <HttpHandlers>

  <HttpHandler pattern="/articles/\d+\.aspx$" controls="viewpost.ascx,Comments.ascx,AnonymousPostComment.ascx,LoginPostComment.ascx" />
   <HttpHandler pattern="/articles/\w+\.aspx$" controls="viewpost.ascx,Comments.ascx,AnonymousPostComment.ascx,LoginPostComment.ascx" />
   <HttpHandler pattern="/PreviewPost.aspx$" controls="PreviewPost.ascx" />
   <HttpHandler pattern="/archive/\d{4}/\d{2}/\d{2}/\d+\.(aspx|htm)$" controls="viewpost.ascx,Comments.ascx,AnonymousPostComment.ascx,LoginPostComment.ascx" />
   <HttpHandler pattern="/archive/\d{4}/\d{2}/\d{2}/\w+\.(aspx|htm)$" controls="viewpost.ascx,Comments.ascx,AnonymousPostComment.ascx,LoginPostComment.ascx" />
   <HttpHandler pattern="/archive/\d{4}/\d{1,2}/\d{1,2}\.aspx$" controls="ArchiveDay.ascx" />
   <HttpHandler pattern="/archive/\d{4}/\d{1,2}\.aspx$" controls="ArchiveMonth.ascx" />
   <HttpHandler pattern="/archives/\d{4}/\d{1,2}\.aspx$" controls="ArticleArchiveMonth.ascx" />
   <HttpHandler pattern="/contact\.aspx$" controls="Contact.ascx" />
   <HttpHandler pattern="/AddToFavorite\.aspx$" handlerType="Page" pageLocation="AddToFavorite.aspx" />
   <HttpHandler pattern="/BlogSearch\.aspx$" controls="BlogSearch.ascx" />
   <HttpHandler pattern="/posts/|/story/|/archive/" type="Dottext.Web.UI.Handlers.RedirectHandler,Dottext.Web" handlerType="Direct" />
   <HttpHandler pattern="/gallery\/\d+\.aspx$" controls="GalleryThumbNailViewer.ascx" />
   <HttpHandler pattern="/gallery\/image\/\d+\.aspx$" controls="ViewPicture.ascx" />
   <HttpHandler pattern="/(?:category|stories)/(\w|\s)+\.aspx$" controls="CategoryEntryList.ascx" />
   <HttpHandler pattern="/favorite/(\w|\s)+\.aspx$" controls="FavoriteList.ascx" />
   <HttpHandler pattern="/(?:admin)" type="Dottext.Web.UI.Handlers.BlogExistingPageHandler, Dottext.Web" handlerType="Factory" />

  </HttpHandlers>
 </HandlerConfiguration>
 
 这里我只想说哈  <HttpHandler pattern="/PreviewPost.aspx$" controls="PreviewPost.ascx" />  类型的配置,  比如这里,我们访问PreviewPost.aspx,那么会
在后台执行 Dottext.Common.UrlManager.HandlerConfiguration的GetHandle
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string path)
  {
                          .....................
                          .....................
      switch(items[i].HandlerType)
      {
       case HandlerType.Page://默认是Page

        return ProccessHandlerTypePage(items[i],context,requestType,url);
       case HandlerType.Direct:
        HandlerConfiguration.SetControls(context,items[i].BlogControls);
        return (IHttpHandler)items[i].Instance();
       case HandlerType.Factory:
        //Pass a long the request to a custom IHttpHandlerFactory
        return ((IHttpHandlerFactory)items[i].Instance()).GetHandler(context,requestType,url,path);
       default:
        throw new Exception("Invalid HandlerType: Unknown");
      }
                              ..............................
                              ....................

  }
  
  而由于这种  PreviewPost.aspx的HandlerType是Page,所以会执行 ProccessHandlerTypePage  .而这个主要执行的工作就是SetControls,即把配置中的这个 "PreviewPost.ascx"保存到HttpContext里面,方便初始化页面的时候调用(调用用GetControls方法);

最后地址仍然是被转向到了default.aspx.
                 
         现在来看初始化default.aspx页面,首先装载用户控件,default.aspx的后台代码是Dottext.Web.UI.Pages.DottextMasterPage,  在OnInit里面执行InitializeBlogPage函数,在这里读取HttpContext里面保存的用户控件名,装载它到MPMain上,而对于default.aspx上的用户控件MasterPage所做的操作是这样的,首先由于在请求时会执行事件AddParsedSubObject,在这里把default.aspx上定义的所有ContentRegion变量存入变量contents里面(即"MPMain").
         然后在MasterPage的OnInit里面做了两件事:
          一个是BuildMasterPage,在这里从BlogConfig里读取模版路径(例如:"WinXPBlue\PageTempalte.ascx"),然后加载它.
          另一个是BuildContents,用来初始化框架上内容这块的. 根据contents里面存储的各个ContentRegion变量名和页面上已经装载的控件想比较,找到contents里面存储的那个ContentRegion变量(即"MPMain"),然后加载它.(注意:因为PageTemplate.ascx也定义了一个ID为MPMain的ContentRegion类的变量,这部做的其实就是加载PageTemplate里面定义的MPMain下的用户控件了)
  
  好了,现在重新来看哈整个执行过程
  1.访问PreviewPost.ascx
  2.将字符串"PreviewPost.ascx"加入到HttpContext
  3.转向到default.aspx
  4.default.aspx加载Context里面存储的 PreviewPost.ascx 到页面上的MPMain上.
  5.default.aspx装载MaterPage
  6.MasterPage加载PageTemplate.ascx,并把它里面的子控件都加载在自己的Controls上.由于MasterPage重写了AddParsedSubObject,所以Default.aspx上的MPMain不会出现在MasterPage的Controls里面
  7.MasterPage处理MPMain,将变量contents里面保存的default.aspx上的MPMain的控件剪切到从PageTemplate.ascx上加载的MPMain上去.
  8.到此default.aspx输出的就是这样的:Head,Foot,Left工具箱是从PageTemplate.ascx上加载来的,而"内容"这块是PreviewPost.ascx了.
  

posted on 2008-03-07 19:07  jasonCao  阅读(380)  评论(0编辑  收藏  举报

导航