再谈CommunityServer模板机制

  在《简化CommunityServer皮肤功能》中我分析了CS皮肤功能的实现原理,如果大家仔细看一下CS中TemplatedWebControl的类我们会发现里边有一个叫AttachChildControls的抽象方法,从字面意思上就可以理解它是用来附加页面控件的。它在各个集体类里得以实现。比如AggregatePagingControl:

 

  private IText prefix;
  
private IButton prevButton;
  
private Repeater pageRepeater;
  
private IButton nextButton;
  
private IText truncateOf;
  
private IButton totalButton;

protected override void AttachChildControls()
  
{
   prefix 
= FindText( "Prefix" );
   prevButton 
= FindButton( "PrevButton" );
   pageRepeater 
= (Repeater)FindControl( "PageRepeater" );
   nextButton 
= FindButton( "NextButton" );
   truncateOf 
= FindText( "TruncateOf" );
   totalButton 
= FindButton( "TotalButton" );

   pageRepeater.ItemDataBound 
+= new RepeaterItemEventHandler(pageRepeater_ItemDataBound);
   pageRepeater.ItemCommand 
+= new RepeaterCommandEventHandler(pageRepeater_ItemCommand);
   prevButton.Click 
+= new EventHandler(page_Click);
   nextButton.Click 
+= new EventHandler(page_Click);
   totalButton.Click 
+= new EventHandler(page_Click);
  }

 


        这个方法实现了TemplatedWebControl中的AttachChildControls。大家注意在这个方法中所有的控件都是通过FindText、FindButton、FindControl等在页面遍历控件进行查找的,这样就会严重影响执行效率。再有一个问题是在CS中实现TemplatedWebControl的各个子类既是ascx控件的代理又是ascx的后台处理程序,显得很乱而且灵活性受到一定影响,比如要求A套模板中的1.ascx和B套模板中的1.ascx模板中的控件数量、类型、名称都必须一致,这样就给我们模板的灵活性带来很大的不利。所以我们将控件代理(模板)、aspx、aspx.cs文件分别独立开来。这样控件代理只负责加载控件,后台代码只负责处理后台程序,ascx只负责前台控件。具体做法如下:

 首先先创建一个控件代理(模板类)ControlTemplate:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ComponentModel;

[assembly: TagPrefix(
"TestTemplate.Controls""ControlTemplate")]
namespace TestTemplate.Controls
{
    
public class ControlTemplate : PlaceHolder
    
{
        
private string _SkinName = "UserControls/Test.ascx";

        [Category(
"皮肤设置")]
        [Description(
"皮肤名称")]
        
public string SkinName
        
{
            
get return _SkinName; }
            
set { _SkinName = value; }
        }


        
protected override void OnLoad(EventArgs e)
        
{
            Page 
= HttpContext.Current.Handler as System.Web.UI.Page;
            
this.Controls.Add(Page.LoadControl(_SkineName));
        }

    }

}


 

注意这是一个具体类不是一个抽象类,它只负责加载控件没有任何其他职能.

第二步,新建一个test.ascx用户控件删除test.ascx.designer.cs和test.ascx.cs文件并添加一个TextBox控件TextBox1
第三步,打开这个用户控件切换到html代码模式,在嘴上边会看到类似它<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Test.ascx.cs" Inherits="TestTemplate.UserControls.Test" %>的代码,把它修改成<%@ Control Language="C#" AutoEventWireup="true" Inherits="TestTemplate.Code.Test" %>。
第四步,新建一个项目Code,添加一个类test并继承UserControl,将命名空间改成TestTemplate.Code。注意:保持命名空间和类名称要与第二步中的Inherits属性一致。

第五部,在test.cs中加入一下代码

 

protected TextBox TextBox1;
protected void Page_Load(object sender, EventArgs e)
{
   TextBox1.Text 
= "OK";
}

 

最后我们拖一个ControlTemplate控件到页面设置SkinName="xxxx/test.ascx"。
ok,运行程序加载成功!这里我只用了一个皮肤文件,用户可以自己根据以上步骤定义很多个模板模板,切换模板的时候我们看到的不仅是界面布局、颜色不同而且功能也可以改变呢,这一点很有用,比如我们判断用户级别高的话我们就调用无验证码的发布控件,用户级别低的话就调用有验证码的控件。这个已经超出了模板的范围,而是一个动态调用的功能了。好了,到此为止我已经介绍完了,它没有使用FindControl,避免了使用FindControl带来的效率损失.同时它将控件代理(模板)、aspx、aspx.cs文件分别独立开来,也增强了模板的灵活性。

 源码下载:http://dl2.csdn.net/down4/20070727/27185334643.rar  

posted @ 2007-08-09 13:27  刘晓飞  阅读(804)  评论(5编辑  收藏  举报