当我们第一眼见到CS的时候你是不是被他那么纷繁复杂的结构看傻眼呢。那么在认识CS之前最好对它的页面间关系做一个全面的了解,这对我门改造CS有较大的帮助。
None.gif       首先我们对整体一个简单的了解,如图,此为在IDE中打开的项目列表:
None.gif
None.gif
None.gif  
None.gif
None.gif       其中CommunityServerWeb项目为IIS运行的WEB项目,项目的UI层相关的都放在此处。CommunityServerComponents和CommunityServerControls都是支持整个系统运行所必须的组件,其中CommunityServerControls项目里有大量的系统公用的控件,由于本系统的几乎所有页面都是由用户控件组合而成的所以需要先了解在CS中用户控件的分布机制。
None.gif
None.gif       CS用户控件:我们知道,用户控件一般以.ascx为扩展名,在建立时都自带了相应的.cs文件,而在CS中考虑到明晰的分层结构和方便的修改UI以及最大程度的换肤功能,程序使用了后台代码与前台UI分开在两个层中,拿常用的CommunityServerControls这个项目来说在项目里我们看不到ascx文件的踪影,原来ascx文件保存在UI层,并且按照各种风格定义了不一样的ascx文件,具体的路径可以参照下图的导航找到:
None.gif
None.gif  
None.gif
None.gif        我们可以看到,在UI层的Themes文件夹里保存了所有在其他层实现的用户控件的ascx文件,我想有必要介绍一下此目录的结构。
None.gif
None.gif        如上图,default文件夹里保存了系统平台使用的默认风格的UI文件,其他文件夹为相应的其他风格的文件集合。当然在此Blogs和Galleries两个文件夹分别是针对博客的皮肤和相册的皮肤,因为这两个项目需要根据具体用户的需要单独制定样式,和网站整体的样式不相关所以单独保存在平行的文件夹里。让我们再看看default文件夹里有些什么,首先是images这个不用说,就是保存了此种风格需要的图片资源,Masters文件夹里保存了页面的整体风格的相关框架,这个在后面详细描述,Skin文件夹里保存的既是大量的用户控件的UI实现,其中命名规则为:skin - ClassName.ascx 其中ClassName为相对应的类名,注意文件名一定要按照这个规则来命名,程序运行的时候,后台的是根据这个名称来找到相应的UI层文件的,这样隔离了依赖关系,前台不用被后台代码束缚了,此种模式我们把它叫着模板用户控件,因为UI层的职责已经很明确了那就是提供控件展现的模板供后台代码调用。
None.gif
None.gif        可以这样来看页面执行过程:用户请求aspx的页面à程序查找页面中的用户控件à实例话用户控件à实例化时根据配置找到相应风格相应名称的ascx文件一并实例化à生成关联后的控件对象返回给aspx页面。这样看来,虽然代码分离了,达到的效果却没有变。
None.gif
None.gif        问题出现了,后台代码和UI层的同步问题,我们在平时建立用户控件或aspx文件的时候IDE自动为我们生成了很多代码,使得我们不需要考虑前台的控件和后台代码的对应问题,而这里代码和UI是分开的,涉及到增加删减控件不同步的问题。要达到用户在UI层删除一个元素之后页面也不会出错,用户随时需要了可以随时修改回去,在CS中是这样处理的,拿登陆的用户控件来看(\src\Controls\Login.cs&\src\Web\Themes\
default \Skins\Skin - Login.ascx)
None.gif
None.gif    如图,这是Login在CommunityServerControls项目里的继承关系,我们的重点应该放在TemplatedWebControl这个类里,此类是所有通过模板方式建立用户控件的基类,在这里包含了处理模板相关的功能,比如命名规则自动找到相应的ascx文件等等,这里注意一下这个的方法:
protected   abstract   void  AttachChildControls();可以看出此方法为抽象的,而且整个类里也就只有这么一个抽象方法,由继承关系我们知道在Login类里必须实现此方法,此方法的作用是干什么的呢,让我们看看Login类里这个方法都干了些什么:
None.gif
None.giflogin.cs
None.gif
None.gifCode highlighting produced by Actipro CodeHighlighter (freeware)
None.gifhttp:
// www.CodeHighlighter.com/
None.gif

ContractedBlock.gifExpandedBlockStart.gif
-->  head head #region head
InBlock.gif
//------------------------------------------------------------------------------
InBlock.gif
// <copyright company="Telligent Systems">
InBlock.gif
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
InBlock.gif
// </copyright> 
InBlock.gif
//------------------------------------------------------------------------------
InBlock.gif

InBlock.gif
using System;
InBlock.gif
using System.Web;
InBlock.gif
using System.Web.Security;
InBlock.gif
using System.Web.UI;
InBlock.gif
using System.Web.UI.WebControls;
InBlock.gif
using CommunityServer.Components;
InBlock.gif
ExpandedBlockEnd.gif
#endregion

None.gif
namespace  CommunityServer.Controls 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    [
InBlock.gif        ParseChildren(
true)
InBlock.gif    ]
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public class Login : SecureTemplatedWebControl  dot.gif{
InBlock.gif
InBlock.gif        CSContext csContext 
= CSContext.Current;
InBlock.gif        TextBox username;
InBlock.gif        TextBox password;
InBlock.gif        IButton loginButton;
InBlock.gif        CheckBox autoLogin;
InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        Other Code
Other Code#region Other Code
InBlock.gif        
// *********************************************************************
InBlock.gif        
//  Login
InBlock.gif        
//
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//**//**//// <summary>
InBlock.gif        
/// Constructor
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        // ***********************************************************************/
InBlock.gif
        public Login() : base() 
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif
InBlock.gif    
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
protected string ReferralLink
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif                
return ViewState["ReferralLink"as string;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif                ViewState[
"ReferralLink"= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
protected override void OnInit(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            
this.EnableViewState = true;
InBlock.gif            
base.OnInit (e);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif
InBlock.gif        
protected override void OnLoad(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif
InBlock.gif
InBlock.gif            
base.OnLoad (e);
InBlock.gif
InBlock.gif            
if(!Page.IsPostBack)
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif                Uri referral 
=  Context.Request.UrlReferrer;
InBlock.gif                
if(referral != null)
InBlock.gif                    ReferralLink 
= referral.ToString();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif
InBlock.gif        
// *********************************************************************
InBlock.gif        
//  CreateChildControls
InBlock.gif        
//
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//**//**//// <summary>
InBlock.gif        
/// This event handler adds the children controls.
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        // ***********************************************************************/
InBlock.gif
        protected override void CreateChildControls() 
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            
// If the user is already authenticated we have no work to do
InBlock.gif
            if(Page.Request.IsAuthenticated)
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif                
// If the URL is for the login page and the user is already logged in
InBlock.gif                
// we need to throw an access denied exception
InBlock.gif
                if (Globals.GetSiteUrls().Login.StartsWith(csContext.Context.Request.Path)) 
InBlock.gif                    
throw new CSException (CSExceptionType.UserAlreadyLoggedIn, csContext.ReturnUrl);
InBlock.gif
InBlock.gif                
return;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
base.CreateChildControls();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif        
protected override void AttachChildControls()
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            
// Find the username control
InBlock.gif
            username = (TextBox) FindControl("username");
InBlock.gif
InBlock.gif            
// Find the password control
InBlock.gif
            password = (TextBox) FindControl("password");
InBlock.gif
InBlock.gif            
// Find the login button
InBlock.gif
            loginButton = ButtonManager.Create(FindControl("loginButton"));
InBlock.gif
InBlock.gif            loginButton.Click 
+= new EventHandler(LoginButton_Click);
InBlock.gif            loginButton.Text 
= ResourceManager.GetString("LoginSmall_Button");
InBlock.gif
InBlock.gif            
// Find the autologin checkbox
InBlock.gif
            autoLogin = (CheckBox) FindControl("autoLogin");
InBlock.gif            autoLogin.Text 
= ResourceManager.GetString("LoginSmall_AutoLogin");        
InBlock.gif            
//autoLogin.AutoPostBack = true;
InBlock.gif            
//autoLogin.CheckedChanged += new EventHandler( AutoLogin_OnCheckedChanged );
InBlock.gif            
InBlock.gif            
// Restore autologin status from the auto login cookie
InBlock.gif
            AutoLoginCookie alCookie = new AutoLoginCookie();
InBlock.gif            autoLogin.Checked 
= alCookie.GetValue();
InBlock.gif
InBlock.gif            RegisterSetFocusScript();
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        Other Codes
Other Codes#region Other Codes
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//**//**//// <summary>
InBlock.gif        
/// Event handler to update auto login cookie value.
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        protected void AutoLogin_OnCheckedChanged (Object sender, EventArgs e) 
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            AutoLoginCookie alCookie 
= new AutoLoginCookie();
InBlock.gif            alCookie.Write( autoLogin.Checked );
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// *********************************************************************
InBlock.gif        
//  LoginButton_Click
InBlock.gif        
//
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//**//**//// <summary>
InBlock.gif        
/// Event handler to handle the login button click event
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        // ***********************************************************************/
ExpandedSubBlockStart.gifContractedSubBlock.gif
        public void LoginButton_Click (Object sender, EventArgs e)  dot.gif{
InBlock.gif            User userToLogin 
= new User();
InBlock.gif            
string redirectUrl = null;
InBlock.gif
InBlock.gif            
// Save in cookie auto login user's preference
InBlock.gif            
// only if it wasn't previously set or the cookie value differs from
InBlock.gif            
// login's autologin checkbox status.
InBlock.gif            
//
InBlock.gif
            AutoLoginCookie alCookie = new AutoLoginCookie();
InBlock.gif            
if (!alCookie.HasValue ||
InBlock.gif                (alCookie.HasValue 
&& (alCookie.GetValue() != autoLogin.Checked))) 
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif                alCookie.Write( autoLogin.Checked );
ExpandedSubBlockEnd.gif            }
 
InBlock.gif
InBlock.gif            
if (!Page.IsValid)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            userToLogin.Username 
= username.Text;
InBlock.gif            userToLogin.Password 
= password.Text;
InBlock.gif            
InBlock.gif            LoginUserStatus loginStatus 
= Users.ValidUser(userToLogin);
InBlock.gif            
bool enableBannedUsersToLogin = CSContext.Current.SiteSettings.EnableBannedUsersToLogin;
InBlock.gif            
InBlock.gif            
// Change to let banned users in
InBlock.gif            
//
InBlock.gif
            if (loginStatus == LoginUserStatus.Success || 
ExpandedSubBlockStart.gifContractedSubBlock.gif                (enableBannedUsersToLogin 
&& loginStatus == LoginUserStatus.AccountBanned))  dot.gif{
InBlock.gif                
// Are we allowing login?
InBlock.gif                
// TODO -- this could be better optimized
ExpandedSubBlockStart.gifContractedSubBlock.gif
                if (!CSContext.Current.SiteSettings.AllowLogin && !userToLogin.IsAdministrator)  dot.gif{
InBlock.gif                    
throw new CSException(CSExceptionType.UserLoginDisabled);
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                    HttpCookie formsAuthCookie;
InBlock.gif                formsAuthCookie 
= FormsAuthentication.GetAuthCookie(userToLogin.Username, autoLogin.Checked);
InBlock.gif                UserCookie userCookie 
= csContext.User.GetUserCookie();
InBlock.gif                userCookie.WriteCookie(formsAuthCookie, 
30, autoLogin.Checked);
InBlock.gif
InBlock.gif                
// Get the link from the context
InBlock.gif
                if ((CSContext.Current.ReturnUrl != null&& (CSContext.Current.ReturnUrl.Trim() != string.Empty))
InBlock.gif                    redirectUrl 
= CSContext.Current.ReturnUrl;
InBlock.gif
InBlock.gif                
// If none, get the stored redirect url
InBlock.gif
                if ((redirectUrl == null&& (ReferralLink != null&& (ReferralLink.Trim() != string.Empty))
InBlock.gif                    redirectUrl 
= ReferralLink;
InBlock.gif
InBlock.gif                
// Check to ensure we aren't redirecting back to a Message prompt or back to the logout screen
InBlock.gif                
// Or ChangePassword*, or CreateUser*, or EmailForgottenPassword*
InBlock.gif                
// Or, if no URL, use appPath
InBlock.gif
                if (Globals.IsNullorEmpty(redirectUrl)
InBlock.gif                    
|| (redirectUrl.IndexOf("MessageID"!= -1)
InBlock.gif                    
|| (redirectUrl.IndexOf(Globals.GetSiteUrls().Logout) != -1)
InBlock.gif                    
|| (redirectUrl.IndexOf("ChangePassword"!= -1)
InBlock.gif                    
|| (redirectUrl.IndexOf("EmailForgottenPassword"!= -1))
InBlock.gif                    redirectUrl 
= Globals.GetSiteUrls().Home;
InBlock.gif
InBlock.gif                LeaveSecureConnection(redirectUrl);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else if (loginStatus == LoginUserStatus.InvalidCredentials)  dot.gif
InBlock.gif                
// Invalid Credentials
InBlock.gif
                Page.Response.Redirect( Globals.GetSiteUrls().Message(CSExceptionType.UserInvalidCredentials), true );
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
else if (loginStatus == LoginUserStatus.AccountPending)  dot.gif
InBlock.gif                
// Account not approved yet
InBlock.gif
                Page.Response.Redirect( Globals.GetSiteUrls().Message(CSExceptionType.UserAccountPending), true );
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
else if (loginStatus == LoginUserStatus.AccountDisapproved)  dot.gif
InBlock.gif                
// Account disapproved
InBlock.gif
                Page.Response.Redirect( Globals.GetSiteUrls().Message(CSExceptionType.UserAccountDisapproved), true );
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else if (loginStatus == LoginUserStatus.UnknownError)  dot.gif
InBlock.gif                
// Unknown error because of miss-syncronization of internal data
InBlock.gif
                throw new CSException(CSExceptionType.UserUnknownLoginError);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
// Reject banned users if they are not allowed to
InBlock.gif            
// pass through login.
InBlock.gif            
//
ExpandedSubBlockStart.gifContractedSubBlock.gif
            else if (!enableBannedUsersToLogin && loginStatus == LoginUserStatus.AccountBanned)  dot.gif
InBlock.gif                
// Account banned
InBlock.gif
                Page.Response.Redirect( Globals.GetSiteUrls().Message(CSExceptionType.UserAccountBanned), true );
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void RegisterSetFocusScript()
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif            
string key = "LoginOnFocus";
InBlock.gif            
if(Page.IsStartupScriptRegistered(key))
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
string script = @"
InBlock.gif                    <script language=""javascript"">
InBlock.gif                    <!--
InBlock.gif                        document.forms[0].{0}.focus()
InBlock.gif                    -->
InBlock.gif                    </script>
";
InBlock.gif      
InBlock.gif            Page.RegisterStartupScript(
"LoginOnFocus"string.Format(script, username.ClientID) ) ;
InBlock.gif            
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
None.gif
None.gif 
None.gif
None.gif看了这个我们应该明白了吧,此方法就是我们手动建立相关控件的关联,使用FindControl(
" controlname " )方法我们就可以找到模板的相应控件所以在定制模板的时候模板里的控件的ID一定要和此处一一对应即可。
None.gif
None.gif        你一定会想,这样一一对应后每每修改前台模板内的控件后不是都要到相应的后台代码里修改相应的代码,不错,是这样,不过还是有相应的对策来弥补这种不足,那就是在后台尽量把前台需要的功能和代码考虑全,这样在前台如果需要去掉某个控件后台的代码也不需要改变,这里后台代码就应该这样写了:
None.gif
None.gifTextBox name 
=  FindControl( " username " as  TextBox;
None.gif
None.gif
if (name  !=   null )
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gif    
//处理代码
InBlock.gif

ExpandedBlockEnd.gif}

None.gif
None.gif        这里可以看出,第一句使用了as语句,作用为把找到的对象转换为TextBox类型,如果没找到或类型转换失败也不引发异常而是将NULL付给变量,这样我们在代码里只需要加多判断引用是否为NULL即可按照我们的想法处理相应逻辑了。
None.gif
None.gif        怕写太多让人没耐心,故分成几篇来分析,后面将介绍在CS中的模板处理机制。 
None.gif
None.gifCS中几乎所有的页面都是靠模板的呈现方式来实现的,那么CS中有些什么样的模板呢,让我们看看CS中的模板机制吧: 
None.gif
None.gif       在我们使用IDE打开Default.aspx页面时,我们仅仅看到一些毫无顺序的控件,几乎看不到控制布局的Html标签,不要困惑,因为在CS中UI层也是按照模板思想分层实现的。先来看看几个类的实现:
None.gif
None.gif打开\src\Controls\ContentContainer.cs
None.gif
None.gif这个文件里分别实现了
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPContainer : MetaBuilders.WebControls.MasterPages.ContentContainer dot.gif {…}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPRegion : MetaBuilders.WebControls.MasterPages.Region dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPContent : MetaBuilders.WebControls.MasterPages.Content dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPForm : MetaBuilders.WebControls.MasterPages.NoBugForm  dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPScript : System.Web.UI.WebControls.PlaceHolder  dot.gif {}
None.gif
None.gif这些类前四个都继承自MetaBuilders.WebControls.MasterPages,那么为什么CS不直接使用这些控件呢,因为这是第三方控件,主动权不在CS中,CS为了隔离控件变动使用了代理模式,这样就可以在程序里使用统一的方法,不用担心以后第三方控件的变动了,同样,在CS系统里还大量运用了此模式,比如在使用FreeTextBox的时候不是直接使用,而是通过Telligent.FreeTextBoxWraper这个类进行封装隔离,并且同时继承自ITextEditor接口,这样程序里面在需要用到文本编辑器的时候只需要引入此接口根据配置加载文本编辑器包装类就可以了,这样处理之后撤卸和安装新扩展都会很容易,如果对此模式还不甚了解的话,我会在后面章节介绍这里的原理。
None.gif
None.gif    好了,了解了这么几个控件类之后就看我们怎样在程序里面使用了,首先简单介绍一下这几个控件类的作用吧:
None.gif
None.gifMPRegion:向页面进行注册的控件,这有点类似于那些大型的新闻静态页面发布系统的标识符,生成静态页面的时候根据标识符替换相应的动态数据。
None.gif
None.gifMPForm :作用很简单,就是为客户端生成Form标签。
None.gif
None.gifMPContainer :包容MPContent控件的容器控件。
None.gif
None.gifMPContent:此控件的ID只要和在Master页面设置的MPRegion控件的ID一致,那么此控件中的内容便自动嵌入到MPRegion控件的位置了,此控件必须用在MPContainer之内。
None.gif
None.gif简单介绍了这些控件之后如果你是初次接触CS那么肯定还会很迷糊,别急,让我们先了解在CS中模板的“继承”关系,虽然不是严格的继承但我们可以这样理解,让我们打开具体的风格文件夹在这里我们看看在\src\Web\Themes\
default \文件夹下的Masters文件夹,此文件夹下大部分都是以Master命名的ascx文件不难从名字可以看出,最主要的文件当然是Master.ascx了,这是所有页面都需要引用的主模板,根据继承的概念我们应该清楚在此文件里应该放一些每个页面都需要用到的Html标签等等,比如页头,公用样式,页面的布局页角以及Form标签等等,如下面的代码:
None.gif
None.gifMaster.ascx
None.gif
None.gifCode highlighting produced by Actipro CodeHighlighter (freeware)
None.gifhttp:
// www.CodeHighlighter.com/
None.gif

None.gif
--><! DOCTYPE html PUBLIC  " -//W3C//DTD XHTML 1.0 Frameset//EN "   " http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd " >  
None.gif
< html xmlns = " http://www.w3.org/1999/xhtml "  xml:lang = " en "  lang = " en " >
None.gif    
None.gif    
< CS:MPRegion id = " HeaderRegion "  runat = " server "   >
None.gif    
None.gif    
< CS:Head runat = " Server " >
None.gif        
< meta http - equiv = " Content-Type "  content = " text/html; charset=iso-8859-1 " >
None.gif        
< CS:Style id = " UserStyle "  runat = " server "  visible  =   " true "   />
None.gif        
< CS:Style id = " s2 "  runat = " server "  visible  =   " true "  Href = " ../style/Common.css "   />
None.gif        
< CS:Style  runat = " server "  Href = " ../style/common_print.css "  media = " print "   />
None.gif        
< CS:Script id = " s "  runat = " server "    />
None.gif    
</ CS:Head >
None.gif    
None.gif    
</ CS:MPRegion >
None.gif    
< body >
None.gif        
< CS:MPForm runat = " server " >
None.gif            
< CS:MPRegion id = " bscr "  runat = " server "   />
None.gif                
< div id = " Common " >
None.gif                    
< div id = " CommonHeader " >
None.gif                        
< CS:MPRegion id = " bhcr "  runat = " server "   >
None.gif                            
< CS:TitleBar runat = " server "  id = " t "   />
None.gif                        
</ CS:MPRegion >
None.gif                    
</ div >
None.gif
None.gif                    
< div id = " CommonBody " >
None.gif                        
< table cellspacing = " 0 "  cellpadding = " 0 "  border = " 0 "  width = " 100% "  id = " CommonBodyTable " >
None.gif                            
< tr >
None.gif                                
< td valign = " top "  id = " CommonLeftColumn " >
None.gif                                    
< CS:MPRegion id = " lcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                                
None.gif                                
< td valign = " top "  width = " 100% "  id = " CommonBodyColumn " >
None.gif                                    
< CS:MPRegion id = " bcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                                
None.gif                                
< td valign = " top "  id = " CommonRightColumn " >
None.gif                                    
< CS:MPRegion id = " rcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                            
</ tr >
None.gif                        
</ table >
None.gif                    
</ div >
None.gif                
None.gif                    
< div id = " CommonFooter " >
None.gif                        
< CS:MPRegion id = " BodyFooterRegion "  runat = " server "   >
None.gif                            
< CS:Footer runat = " server "  id = " Footer1 " />
None.gif                        
</ CS:MPRegion >
None.gif                    
</ div >
None.gif                
</ div >
None.gif            
</ CS:MPRegion >
None.gif        
</ CS:MPForm >
None.gif    
</ body >
None.gif
</ html >
None.gif
None.gif        从代码中我们可以看出MPRegion和MPForm这两个元素,也就是告诉“继承”自这个页面的控件什么地方应该嵌入什么。比如
< CS:MPRegion id = " HeaderRegion "  runat = " server "   > 这个标签表示如果子页面有id为HeaderRegion的MPContent这个控件对象的时候,那么此控件中的内容将插入到此处替换调默认的内容,如果子页面不存在此ID的MPContent的话则使用此标签内的内容。
None.gif
None.gif        其他文件,比如HomeMaster.ascx文件表示首页的模板,此模板的基本模板还是使用Master.ascx这就好比类的继承关系,Master是基类,HomeMaster是首页的基类,
default .aspx则是继承自HomeMaster的子类,只是需要在首页的MPContainer标签处标明使用哪一个模板即可,如 < CS:MPContainer runat = " server "  id = " Mpcontainer1 "  ThemeMasterFile  =   " HomeMaster.ascx "   > 一个好处就是尽量减少了重复的公用HTML标签,另外一个好处是页面可以分层,比如在设计一个较复杂的首页时,我们可以把大量的复杂的Html标签放在HomeMaster只在需要插入动态内容的地方注册MPRegion标签,这样做后我们只需要在首页里使用MPContent包含相应的动态内容而不需要被复制的Html标签搞昏了头。这就是为什么我们初次打开首页几乎看不到控制首页格式的HTML标签的原因。同理,其他模块也是如此这般,这里就不冗诉了。
None.gif
None.gifCS中几乎所有的页面都是靠模板的呈现方式来实现的,那么CS中有些什么样的模板呢,让我们看看CS中的模板机制吧: 
None.gif
None.gif       在我们使用IDE打开Default.aspx页面时,我们仅仅看到一些毫无顺序的控件,几乎看不到控制布局的Html标签,不要困惑,因为在CS中UI层也是按照模板思想分层实现的。先来看看几个类的实现:
None.gif
None.gif打开\src\Controls\ContentContainer.cs
None.gif
None.gif这个文件里分别实现了
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPContainer : MetaBuilders.WebControls.MasterPages.ContentContainer dot.gif {…}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPRegion : MetaBuilders.WebControls.MasterPages.Region dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPContent : MetaBuilders.WebControls.MasterPages.Content dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPForm : MetaBuilders.WebControls.MasterPages.NoBugForm  dot.gif {}
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  MPScript : System.Web.UI.WebControls.PlaceHolder  dot.gif {}
None.gif
None.gif这些类前四个都继承自MetaBuilders.WebControls.MasterPages,那么为什么CS不直接使用这些控件呢,因为这是第三方控件,主动权不在CS中,CS为了隔离控件变动使用了代理模式,这样就可以在程序里使用统一的方法,不用担心以后第三方控件的变动了,同样,在CS系统里还大量运用了此模式,比如在使用FreeTextBox的时候不是直接使用,而是通过Telligent.FreeTextBoxWraper这个类进行封装隔离,并且同时继承自ITextEditor接口,这样程序里面在需要用到文本编辑器的时候只需要引入此接口根据配置加载文本编辑器包装类就可以了,这样处理之后撤卸和安装新扩展都会很容易,如果对此模式还不甚了解的话,我会在后面章节介绍这里的原理。
None.gif
None.gif    好了,了解了这么几个控件类之后就看我们怎样在程序里面使用了,首先简单介绍一下这几个控件类的作用吧:
None.gif
None.gifMPRegion:向页面进行注册的控件,这有点类似于那些大型的新闻静态页面发布系统的标识符,生成静态页面的时候根据标识符替换相应的动态数据。
None.gif
None.gifMPForm :作用很简单,就是为客户端生成Form标签。
None.gif
None.gifMPContainer :包容MPContent控件的容器控件。
None.gif
None.gifMPContent:此控件的ID只要和在Master页面设置的MPRegion控件的ID一致,那么此控件中的内容便自动嵌入到MPRegion控件的位置了,此控件必须用在MPContainer之内。
None.gif
None.gif简单介绍了这些控件之后如果你是初次接触CS那么肯定还会很迷糊,别急,让我们先了解在CS中模板的“继承”关系,虽然不是严格的继承但我们可以这样理解,让我们打开具体的风格文件夹在这里我们看看在\src\Web\Themes\
default \文件夹下的Masters文件夹,此文件夹下大部分都是以Master命名的ascx文件不难从名字可以看出,最主要的文件当然是Master.ascx了,这是所有页面都需要引用的主模板,根据继承的概念我们应该清楚在此文件里应该放一些每个页面都需要用到的Html标签等等,比如页头,公用样式,页面的布局页角以及Form标签等等,如下面的代码:
None.gif
None.gifMaster.ascx
None.gif
<! DOCTYPE html PUBLIC  " -//W3C//DTD XHTML 1.0 Frameset//EN "   " http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd " >  
None.gif
< html xmlns = " http://www.w3.org/1999/xhtml "  xml:lang = " en "  lang = " en " >
None.gif    
None.gif    
< CS:MPRegion id = " HeaderRegion "  runat = " server "   >
None.gif    
None.gif    
< CS:Head runat = " Server " >
None.gif        
< meta http - equiv = " Content-Type "  content = " text/html; charset=iso-8859-1 " >
None.gif        
< CS:Style id = " UserStyle "  runat = " server "  visible  =   " true "   />
None.gif        
< CS:Style id = " s2 "  runat = " server "  visible  =   " true "  Href = " ../style/Common.css "   />
None.gif        
< CS:Style  runat = " server "  Href = " ../style/common_print.css "  media = " print "   />
None.gif        
< CS:Script id = " s "  runat = " server "    />
None.gif    
</ CS:Head >
None.gif    
None.gif    
</ CS:MPRegion >
None.gif    
< body >
None.gif        
< CS:MPForm runat = " server " >
None.gif            
< CS:MPRegion id = " bscr "  runat = " server "   />
None.gif                
< div id = " Common " >
None.gif                    
< div id = " CommonHeader " >
None.gif                        
< CS:MPRegion id = " bhcr "  runat = " server "   >
None.gif                            
< CS:TitleBar runat = " server "  id = " t "   />
None.gif                        
</ CS:MPRegion >
None.gif                    
</ div >
None.gif
None.gif                    
< div id = " CommonBody " >
None.gif                        
< table cellspacing = " 0 "  cellpadding = " 0 "  border = " 0 "  width = " 100% "  id = " CommonBodyTable " >
None.gif                            
< tr >
None.gif                                
< td valign = " top "  id = " CommonLeftColumn " >
None.gif                                    
< CS:MPRegion id = " lcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                                
None.gif                                
< td valign = " top "  width = " 100% "  id = " CommonBodyColumn " >
None.gif                                    
< CS:MPRegion id = " bcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                                
None.gif                                
< td valign = " top "  id = " CommonRightColumn " >
None.gif                                    
< CS:MPRegion id = " rcr "  runat = " server "   />
None.gif                                
</ td >
None.gif                            
</ tr >
None.gif                        
</ table >
None.gif                    
</ div >
None.gif                
None.gif                    
< div id = " CommonFooter " >
None.gif                        
< CS:MPRegion id = " BodyFooterRegion "  runat = " server "   >
None.gif                            
< CS:Footer runat = " server "  id = " Footer1 " />
None.gif                        
</ CS:MPRegion >
None.gif                    
</ div >
None.gif                
</ div >
None.gif            
</ CS:MPRegion >
None.gif        
</ CS:MPForm >
None.gif    
</ body >
None.gif
</ html >
None.gif
None.gif        从代码中我们可以看出MPRegion和MPForm这两个元素,也就是告诉“继承”自这个页面的控件什么地方应该嵌入什么。比如
< CS:MPRegion id = " HeaderRegion "  runat = " server "   > 这个标签表示如果子页面有id为HeaderRegion的MPContent这个控件对象的时候,那么此控件中的内容将插入到此处替换调默认的内容,如果子页面不存在此ID的MPContent的话则使用此标签内的内容。
None.gif
None.gif        其他文件,比如HomeMaster.ascx文件表示首页的模板,此模板的基本模板还是使用Master.ascx这就好比类的继承关系,Master是基类,HomeMaster是首页的基类,
default .aspx则是继承自HomeMaster的子类,只是需要在首页的MPContainer标签处标明使用哪一个模板即可,如 < CS:MPContainer runat = " server "  id = " Mpcontainer1 "  ThemeMasterFile  =   " HomeMaster.ascx "   > 一个好处就是尽量减少了重复的公用HTML标签,另外一个好处是页面可以分层,比如在设计一个较复杂的首页时,我们可以把大量的复杂的Html标签放在HomeMaster只在需要插入动态内容的地方注册MPRegion标签,这样做后我们只需要在首页里使用MPContent包含相应的动态内容而不需要被复制的Html标签搞昏了头。这就是为什么我们初次打开首页几乎看不到控制首页格式的HTML标签的原因。同理,其他模块也是如此这般,这里就不冗诉了。

转载于:https://www.cnblogs.com/guodapeng/archive/2007/12/21/1009030.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐