让我们来做个页面模版吧!有了模版是不是就可以统一了呢!
Sure
!
比如:模版页
Template.ascx
中我们留出中间一个部分,或者你想要留出的一个空间,让以后放入你想要的内容。
好了!那么在我们的页面
index.aspx
上我们就可以引用这个
Template.ascx,
然后在空出的部分放入我们特别的东西,当然最好是在空的地方我们插入另外一个页面如:
List.ascx
,
当然我们在做个页面
MyArchive.aspx.
同样的我们引用这个
Template.ascx,
然后再在空出大那个地方我们插入了另外一个页面
Archive.ascx.
非常好。我们要的两个
index.aspx.
和
MyArchive.aspx
页面是不是一样的呢?就只有我们留空的那一个地方不一样而已。
当然这样的应用可以是各种各样,可以不用框架集而达到更完美的效果。而你的页面完全可以没有重复的东西。因为我们的页面完全是组装而成的!
那么有了这个美妙的想法之后我们就开始去实现。
技术点:
1
、怎么留出一个空间出来,然后还要让引用页找到这个空间。
2
、怎么引用模版而且还要找出留出的空间。
3
、怎么引用另外一页插入我们在模版页中留出的空间。
其实所有这些就需要用到三个组件,一个是用来保留的空间,一个是用来引用页面放入到我们保留出来的空间,这两个组件其实只是起到标记的作用而已。另一个也是主要的一个就是引用模版,然后处理引用页面并插入到模版中去。
1
、我们来解决的一个技术问题,留个空间很容易的就是
PlaceHolder
,
那么我们还要考虑到
ID
的问题
,
因为我们还要找到这个地方,当然我们可能要留几个不同的地方,这样就很有必要处理一下
ID
的问题。那么扩展
PlaceHolder
同时继承
INamingContainer
。
我们取名为:
PlugArea
那么这个主要做的事情有两件事,把本身保存起来,然后在第三个组件用到的时候取出来。
public
class PlugArea : PlaceHolder, INamingContainer {
public override string ID {
get {
return base.ID;
}
set {
base.ID = value;
AddToContext();
}
}
private static readonly String contextKey = "Region.MasterPages.Region";
private void AddToContext() {
if ( HttpContext.Current != null ) {
String myKey = contextKey + this.ID;
if ( HttpContext.Current.Items.Contains(myKey) ) {
throw new InvalidOperationException("
这个
ID'"
+ this.ID + "'
已经用了啦!
."
);
} else {
HttpContext.Current.Items[myKey] = this;
}
}
}
internal static PlugArea FindPlugArea( String ID ) {
if ( HttpContext.Current == null ) {
return null;
}
return HttpContext.Current.Items[contextKey + ID] as PlugArea;
}
}
|
那么我们的
Template.ascx
可以写成这样
<
%@ Control %>
<
%@ Register TagPrefix="Region" Namespace="Region.Controls" Assembly="Region.Controls" %>
<
HTML
>
<HEAD>
<title>
信息管理系统
</
title
>
</HEAD>
<bodyleftmargin="0"topmargin="0"marginwidth="0"marginheight="0"> <formrunat="server"id="Form1">
<tablewidth = 800align=center border=0cellpadding=0cellspacing=0><tr><td>
相同的第一部分
</td></tr><tr><td>
<Region:PlugAreaid="part1"runat="server"/> </td></tr><tr><td>
相同的第二部分
</td></tr><tr><td>
<Region:PlugAreaid="part2"runat="server"/>
</td></tr><tr><td>
相同的第三部分
</td></tr></table>
</form>
</body>
</
HTML
>
|
2
、引用模版页的时候,在里面标记以下我们保留的空间应该插入哪个页面,标记以下就可以了!具体的事情由引用模版页的组建来搞定。继承
PlaceHolder
组建起名:
SignArea
两件事情:一、只需把
ID
设成我们要插入那个空间组件的
ID.
二、在后面把这个插入我们留出的空间的时候,把组建的路径设成一样的,避免路径不一样引起异常发生。
当然,我们要在这个
SignArea
内应用我们的页面。
public
class
SignArea
: PlaceHolder {
internal string Directory;
public override string TemplateSourceDirectory {
get {
return Directory;
}
}
}
|
我们可以这样用:
<
Region:
SignArea
id
=
" part1"runat="server">
这里可以用我前面的文章讲
LoadSky
来来引用用户页面,或直接写内容放这里。
</
Region:
SignArea
>
<
Region:
SignArea
id
=
" part2"runat="server">
同上第一部分。
</
Region:
SignArea
>
|
3
、应用我们的模版页并处理其中的模块插入。
继承
PlaceHolder
继
命名:
LoadTemplate
做事情:一、重载
AddParsedSubObject
事件,在记录
PlaceHolder
中的
SignArea
二、加载
Template
页。
三、根据
SignArea
的
id
找到
PlugArea
(用
PlugArea
内的
FindPlugArea
,也就是为什么要用静态方法的原因
),然后把
SignArea
插入到
PlugArea
中去。
这三件事做完事情也就做完了
看一下代码:
public
class LoadTemplate : PlaceHolder {
private ArrayList signarealist = new ArrayList();
protected override void AddParsedSubObject(object obj)
{
if (obj is SignArea) {
signarealist.Add(obj);
}
}
protected override void OnInit(EventArgs e) {
this.GetTemplate();
base.OnInit(e);
}
private void GetTemplate() {
if (TemplateFilePath == null) {
throw new Exception("ûÓÐÄ£°åÒ³£¡");
}
Controls.Add(Page.LoadControl(TemplateFilePath));
SignAreaInsertIntoPlugArea();
}
private void SignAreaInsertIntoPlugArea() {
foreach (SignArea signarea in signarealist) {
PlugArea plugarea = PlugArea.FindPlugArea(signarea.ID);
if (plugarea == null ) {
throw new Exception("ÕÒ²»µ½²åÈëµÄ¿Õ¼ä'" + signarea.ID + "'");
}
SignArea.Directory = TemplateSourceDirectory;
plugarea.Controls.Clear();
plugarea.Controls.Add(signarea);
}
}
public string TemplateFilePath{
get {
return (string)ViewState["TemplateFilePath"];
}
set {
ViewState["TemplateFilePath"] = value;
ChildControlsCreated = false;
}
}
}
|
好我们来看看怎样引用模版页!
index.aspx
页面:
<
%@ Page %>
<
%@ Register TagPrefix="Region" Namespace="Region.Controls" Assembly="Region.Controls" %>
<
Region: LoadTemplate
runat
=
"server"id="LoadTemplate "TemplateFilePath ="~/Template.ascx">
<Region:
SignArea
id
=
"part1"runat="server">
<Region:
LoadSky
id
=
"Sky1" skinPath="~/List.ascx "runat="server"/>
</
Region:
SignArea
>
<
Region:
SignArea
id
=
"part2"runat="server">
<Region:
LoadSky
id
=
"Sky2" skinPath="~/
MyArchive
.ascx
"runat="server"/>
</
Region:
SignArea
>
</
Region:LoadTemplate
>
|
那么运行一下完整的一个页面就出现在我们面前了。当然可以这样生成所有想要的一样风格的页面。
从一开始写到现在,最后这里就变成了传说中的那个
Masterpages
的技术。
就如同天下武学都源自少林一样
但是怎样灵活的在项目中运用呢?怎样做到面向组件的开发呢?就像是积木式开发,我们的叶面可以有不同的组件来完成,而整个叶面就是一个容器,我们只不过是往容器里添加不同的元素而已,因此只要我们的元素能够做到通用,一般化,那么元素积累到了一定的程度,元素足够的丰富就可以经而一举构造出我们想要得叶面。
更多地运用到下一篇文章再详细到来。下面我们先来看看怎么样加载组合我们的用户组件:
1
、让我们来先做两个元素,这里我就把用户组件
ascx
的文件称之为元素了。
Head.ascx
和
Footer.ascx.
2、作个aspx叶面来加载着两个元素。
3、运行的效果如下:
哈哈!是不是很激动人心呢?
好让我们来动态加载,让头脚换一下位置怎么样!我们在aspx叶面上加一个按钮,在按钮的相应事件里改变加载不同的用户组件。事件的代码这样写:
运行之后:
赶快按下鼠标试试看
哈啊!是不是头脚换了位置了呢?
好!动态加载用户组件搞定。可以 Release 一下了。
那么这只是一个简单的应用,让我们期待下一篇文章再来领略动态加载组建的真正的应用。
坐着沙发等吧...
未完(持续)
页面是用来浏览信息的!但是更重要的是和用户交互,根据不同的需求提供不同的内容服务,这是一种服务或是一种更贴近用户的人性化。(又在胡言乱语了!
^_^
)
动态加载叶面,根据不同的用户权限加载不懂的内容服务。根据用户的相应加载相应的内容服务。
还有另外一个应用就是做到页面与代码的分离。在
vs2003
里,一般
ascx
或
aspx
文件,在刚建立的时候都直接跟一个
cs
文件关联。那么我们在写程序的时候就不能分开来做。作叶面和写后台代码的不能分开。为了能够做到作业面与作后台代码的能完全分开来,我们可以把后台的所有代码当作一个组件来做就可以了!这样一个不用跟
cs
文件关联的
aspx
叶面文件直接引用一个组件就可以了!那么组件可以加载不同的
ascx
文件最后组成一个完整的叶面。就这样一个项目的开发就像个机车制造厂一样组装不同的零件就有辆车出来了。软件也可以拿来组装,零件我们也可以订制,最后整体就可以出来了!(常常看别人的文章的时候怎么就觉得废话那么多,原来发现我废话也不少!
^_^
)
好!让我们step by step ,就从不需要关联cs文件的aspx叶面开始吧!(在vs2005里,我新建aspx叶面的时候就直接没有cs文件关联。但是直接有个不完整类型隐藏起来了。怎么用基类就成为问题了!隐藏部分应该是继承了Page了!那么根据单继承的原则我们是不能在继承别的类型的了。这个问题有待研究。)
根据aspx叶面运行原理。叶面要跟服务端交互必须通过一个run at server的form标签才能行得通。因此我不要先来写个form组件,那么form就应该是个容器的形势来承载叶面所有要与服务端交互的元素,(容器太重要了,namespace也可以看作容器,只不过是不能放东西而已,是虚拟的容器)
1、做form容器组建:继承继承他就行了,注意一点就是唯一ID的问题。自己继承的可能该改变了ID,那么回传的时候就找不到了啊。切记!当然render叶面的时候是通过遍历所有form容器内所有的组件来一个个render出来。所以要改
UniqueID。
示例一下:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace Region.Controls {
public class MyForm : System.Web.UI.HtmlControls.HtmlForm {
public override string UniqueID {
get {
if (this.NoNameContainer && this.NamingContainer != this.Page ) {
return base.UniqueID.Substring(base.UniqueID.LastIndexOf(":")+1);
} else {
return base.UniqueID;
}
}
}
protected override void RenderAttributes(HtmlTextWriter writer) {
this. NoNameContainer = true;
base.RenderAttributes (writer);
this. NoNameContainer = false;
}
protected override void RenderChildren(HtmlTextWriter writer) {
this. NoNameContainer = true;
base.RenderChildren (writer);
this. NoNameContainer = false;
}
private Boolean NoNameContainer = false;
}
}
|
未完(持续)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=78758
[
点击此处收藏本文] 发表于 2004年08月19日 10:03 AM
href="http://blog.csdn.net/xinyulou/Services/Pingback.aspx" rel="pingback" />
<script>document.write("");</script>
Ping Back来自:blog.csdn.net
我用word写的!放到这里就成这个样子了,也是没有办法