1.继承TemplateControl/usercontrol/page中的一个,因为是要回传的视图状态,所以选择了usercontrol,比较适合定义视图状态
public class BaseUserControl:UserControl
{
private Control skin;
public Control Skin { get { return skin; } }
public BaseUserControl()
{
///此处定义了要调用的ascx文件的路径,其中的一切变量希望大家忽略,实在与本例无关
string path = "{0}MasterPages/{1}/UserControls/{2}.ascx";
string ascxFileName = this.GetType().Name;
string virpath = String.Format(path, HttpRuntime.AppDomainAppVirtualPath, StaticMethod.CurrentUser.MasterPage, ascxFileName);
if (!File.Exists(HttpContext.Current.Server.MapPath(virpath)))
{///指定的文件如果存在,从此处载入ascx文件
virpath = String.Format(path, HttpRuntime.AppDomainAppVirtualPath, Gloable.MasterPage, ascxFileName);
if (!File.Exists(HttpContext.Current.Server.MapPath(virpath)))
{//如果默认的ascx文件也不存在,则返回一个新的Literalcontrol或抛出异常
//throw (new Exception(String.Format(StaticMethod.GetMessage("FileNotFind"), virpath)));
Literal lit=new Literal();
lit.Text = String.Format("{0} Not Found", virpath);
skin = lit;
}
else {
skin = LoadControl(virpath);
}
}
Controls.Add(skin);
}
}
2:ascx文件
<asp:Repeater runat="server" ID="Rep_CacheStrategys">
<HeaderTemplate>
<table id="TabCacheStrategys">
<tr>
<td>关键字</td>
<td>说明</td>
<td>缓存策略</td>
<td>缓存时间(毫秒)</td>
<td>缓存代价</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><asp:Label runat="server" id="Lab_Key" ></asp:Label></td>
<td><asp:Label runat="server" ID="Lab_Description"></asp:Label></td>
<td><asp:DropDownList runat="server" ID="DDL_Strategy">
<asp:ListItem Value="Dependency">依赖缓存</asp:ListItem>
<asp:ListItem Value="Absolute">绝对缓存</asp:ListItem>
<asp:ListItem Value="Relative">相对缓存</asp:ListItem>
<asp:ListItem Value="None">不缓存</asp:ListItem>
</asp:DropDownList></td>
<td><asp:TextBox runat="server" ID="TB_Expiration"></asp:TextBox></td>
<td><asp:DropDownList runat="server" id="DDL_Priority">
<asp:ListItem Value="NotRemovable">不可移除</asp:ListItem>
<asp:ListItem Value="AboveNormal">最高优先级</asp:ListItem>
<asp:ListItem Value="High">略高</asp:ListItem>
<asp:ListItem Value="Normal">正常</asp:ListItem>
<asp:ListItem Value="Low">略低</asp:ListItem>
<asp:ListItem Value="BelowNormal">最低优先级</asp:ListItem>
</asp:DropDownList></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</Table>
</FooterTemplate>
</asp:Repeater>
3.继续baseusercontrol实现usercontrol的展示
public class CacheStrategys:BaseUserControl
{
public CacheStrategys() : base() {
//实现数据绑定Cacheddatas.CachedData.CacheStragegyCollection是一个CacheStragegyItem数组
//同样与本例无关,请忽略之
Repeater Rep_CacheStrategys = (Repeater)Skin.FindControl("Rep_CacheStrategys");
if (Rep_CacheStrategys != null) {
Rep_CacheStrategys.ItemDataBound += new RepeaterItemEventHandler(Rep_CacheStrategys_ItemDataBound);
Rep_CacheStrategys.DataSource = Cacheddatas.CachedData.CacheStragegyCollection;
Rep_CacheStrategys.DataBind();
}
}
void Rep_CacheStrategys_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
//throw new Exception("The method or operation is not implemented.");
//实现数据绑定的过程省略
}
}
4.好了,我们现在有一个usercontrol了,下一步的目标是从实现了icallbackeventhandler接口的page将它回传给客户端.因为我比较容易忘事,所以一样先做了一个basepage的抽象基类,这一步是可以省略的, 可以直接由page来实现它
public abstract class BasePage:Page,ICallbackEventHandler
{
public string _Result;
public abstract void RaiseCallbackEvent(string arg);
public abstract string GetCallbackResult();
}
5实现basepage,可以从RaiseCallbackEvent得到客户端的请求,传回_Result用于展现ascx;
public class AppSettings:BasePage
{
public override void RaiseCallbackEvent(string argu)
{
try
{
String[] args = argu.Split(new char[] { '|' }, 2);
if (args.Length == 2)
{
string command = args[0];
string arg = args[1];
switch (command)
{//如果传回的是LoadAscxFile|ascxfilename格式的参数.
//其它的参数格式与本例无关省略之.如果command过多,可以考虑反射
case "LoadAscxFile":
_Result = LoadAscxFile(arg);
break;
default:
_Result = StaticMethod.GetMessage("BadCommand");
break;
}
}
else
{
_Result = StaticMethod.GetMessage("BadCommand");
}
}
catch (Exception excep) { _Result = excep.ToString(); }
}
public override string GetCallbackResult()
{
return _Result;
}
private string LoadAscxFile(string ascxFileName) {
try {
//这是一个权限验证,可省略
if (!StaticMethod.ValidateUserRight(ascxFileName)) {
return StaticMethod.GetMessage("InvalidateOperation");
}
else
{
//由ascxfilename反射得到类实例,比如刚才第2,3步实现的CacheStrategys
//的表现层和逻辑层(ascx/cs)
Type t = Type.GetType("Hubei.Blackant.Controls." + ascxFileName);
BaseUserControl buc = (BaseUserControl)Activator.CreateInstance(t);
//将usercontrol写入到StringWriter,回传
//在此感谢CSDN社区reaperwu(RQ)的帮助
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
buc.RenderControl(htw);
return sw.ToString();
}
}
catch (Exception excep){
return excep.ToString();
}
}
6好了,做了一大堆事,事实上我们什么也没有得到,还没有页面来实现它呢,55555,多简单的事让我们弄复杂了
<!--这儿的Inherits由第5步实现,55555,上面没有定义namespace-->
<%@ Page Language="C#" Inherits="Hubei.Blackant.AppSettings" ClassName="AppSettings"%>
<%@ Register TagPrefix="bawc" Namespace="Hubei.Blackant.Controls" Assembly="Hubei.Blackant"%>
<asp:Content ContentPlaceHolderID="HeadTag" runat="server" ID="HeadContext">
<script type="text/javascript">
<!--
function loadAscxFile(ascxfile){
var command="LoadAscxFile|"+ascxfile;
var content=true;//这个content实在不知道有什么用,在ClientScriptManager中要实现
//但是在服务端并不会被接收,而是直接回传给客户端回叫函数
<%=ClientScript.GetCallbackEventReference(this,"command","ShowClientContext","content")%>
}
function ShowClientContext(result,context){
//也许传回context的本意是想让result和context关联,但是总觉得多余
//很多示例在这儿是用result来改变context的属性
var ClientContext=document.getElementById("ClientContext");
ClientContext.innerHTML=result;
}
//-->
</script>
<a href="javascript:LoadAscxFile('CacheStrategys');">Test</a>
<div id="ClientContext">
</div>
7好了,基本上能用了,我们再来回顾一下整个事件过程,这次倒着来,不是由实现的倒序,而是由事件的激发过程用实先click第6步中的anchor会激发javascript定义的LoadAscxFile,在LoadAscxFile中由ClientScriptManager.GetCallbackEventReference激发服务端事件,也就是第五步中的RaiseCallbackEvent,事件接收了LoadAscxFile|CacheStrategys参数,分解后会调用LoadAscxFile方法,LoadAscxFile由反射得到第3步中定义的CacheStrategys实例,CacheStrategys会调用第2步中的ascx文件做为样式,好了,有了这样的用usercontrol来做表现层之后(个人认为这是个比较合理的选择,其实也可以试着由TempableControl来实现,不知道为什么一开始就想到了UserControl),再回到第LoadAscxFile,它会返回CacheStrategys实例的html格式表现方式,并由RaiseCallbackEvent赋值给_Result,然后由GetCallbackResult返回给客户端,客户端再由ClientScriptManager.GetCallbackEventReference定义的回叫方法,此处是ShowClientContext来实现这个html的展现
ps:祝大家开开心心每一天,重要的是写的不好不要骂我,如有错误请写信给我指正blackant@tt88.cn,另有一个问题想请达人指点,如果usercontrol中定义了javascript,返回是客户端能接收到,但其中的定义无效,可能需要document.write(scriptdefine),但是毕竟这样不合理,有好办法解决的也请一并mail2me