根据Asp.net 2.0的MasterPage应用,我们知道: 1. MasterPage里面包含ContentPlaceHolder控件用做为具体内容的容器 2. 使用母版页的页面包含Content控件提供具体内容 3. 页面展现时,会将MasterPage的内容展现出来,并把Content控件下的内容填充到ContentPlaceHolder中。
仿照Asp.net 2.0,对应到Asp.net 1.1下面应该是: 1. 做两个自定义控件,分别叫做ContentPlaceHolder和Content 2. MasterPage是一个用户控件(ascx),里面包含ContentPlaceHolder控件做为具体内容的容器 3. 使用母版页的页面包含Content控件提供具体内容 4. 页面展现时,会将MasterPage的内容展现出来,并把Content控件下的内容填充到ContentPlaceHolder中。
是啊,就这么简单,没啥特别的东西,但没看到Spring.net之前,怎么就没想过去实现这么个MasterPage呢?
前面说了,ContentPlaceHolder是内容的容器,Content控件是具体的内容,他们的代码如下: Content.cs:
可以看到,Content控件包含一个属性ContentPlaceHolderID,用以指向母版页的ContentPlaceHolder控件。 ContentPlaceHolder.cs:
ContentPlaceHolder控件拥有一个属性Content,指向一个Content控件实例,在下面的代码中你会看到它是何时被赋值的。同时,ContentPlaceHolder重写了Control控件的Render方法,当它拥有一个Content控件的实例的时候,展现Content控件的内容,否则,展现自己的内容(用于展现默认内容)。 注意PersistChildren(true)和ParseChildren(false),这两句指定了这两个控件是可以包含子控件的,这非常重要,因为不管是ContentPlaceHolder,还是Content控件,都需要拥有子控件(ContentPlaceHolder用子控件来表示默认的内容,Content用子控件表示具体的要替换的内容)。 上面说到,ContentPlaceHolder控件拥有一个属性Content,指向一个Content控件实例,那么,这个实例是什么时候被赋值的呢? 我们知道,MasterPage应该是一个用户控件,并且ContentPlaceHolder控件是包含在MasterPage控件里的,所以,我们应该在MasterPage里去初始化ContentPlaceHolder的Content属性。在页面初始化时,根据页面的MasterPageFile属性,加载MasterPage控件,然后初始化该控件里的ContentPlaceHolder。这样,我们就需要另外两个类,MasterPage基类和Page基类,分别对应母版控件和使用母版的页面。 3 Page和MasterPage Page.cs:
Page类重写了OnInit方法,并在OnInit时,调用MasterPage类的Initialize方法初始化母版。另外,它重写了Render方法,当母版存在的时候,展现母版的内容。
MasterPage.cs:
在母版的初始化方法里,它遍历了子页面的第一层控件来寻找Content控件,然后根据Content控件实例的ContentPlaceHolderID属性,从自身找到相对应的ContentPlaceHolder控件,然后把Content控件的实例赋值给ContentPlaceHolder控件,从而达到初始化的目的,最后,母版把自己做为一个控件,加到子控件里(childPage.Controls.AddAt(0,this),这句话非常重要,少了这句会带来PostBack时的异常。 注意,上面的初始化方法,只是遍历了子页面的第一层控件来寻找Content控件,这就要求我们的子页面(即使用母版的页面)的Content控件不能放在runat=server的Form内了,因为如果控件位于runat=server的form内,页面的第一层控件里就遍历不到Content控件了,因为他们属于HtmlForm控件的子控件。当然,如果您非要在子控件的Content控件外层放置一个runat=server的form的话,那就要修改一下上面的这段代码了。 到这里为止,这个MasterPage的功能就被我们实现了,代码比较简单,下面简单介绍一下如何使用。 4 如何使用 它的使用方法和Asp.net 2.0下的MasterPage使用方法一样。 首先我们定义一个母版页,后台代码继承与上面定义的基类MasterPage:
在这个母版里,定义了三个ContentPlaceHolder,分别表示页面的Title,Head和Content。
然后定义一个使用该模板的子页面(后台代码继承与上面定义的基类Page):