| ||||||||||
IntroductionASP.NET 2.0 introduces a great new feature called Master Pages, which provides a framework for creating page templates that can be reused across a Web application. However, since ASP.NET 2.0 is currently in beta, much of the development community cannot realize the benefits of Master Pages today. The goal of this article is to demonstrate a framework for creating page templates in ASP.NET 1.1, the Page Template Framework, which provides similar functionality to Master Pages and is organized in such a way to be easily migrated to the Master Pages framework. There are many articles floating around the Web that offer solutions for creating page templates in ASP.NET 1.1. I spent much time looking over these articles and discovered that there were many ways to accomplish the task. However, I had yet to find a solution that fit my needs. One of the articles I had read, Peter Provost’s ASP.NET Page Templates – Using Inheritance, prompted a proverbial “light bulb” to appear over my weary head. I have worked with ColdFusion for many years, and one of the frameworks available for ColdFusion development – Fusebox – utilizes a “circuit” to organize the structure of components within a page. This same idea could be merged with page inheritance to provide a dynamic and scalable solution for page templates in ASP.NET 1.1. Configurable Page TemplatesAlmost every article I researched when considering this framework offered a solution that required a predefined page template be developed. This meant that any change to be made to the template would require the Web application to be recompiled and redeployed to the Web server. Although this may seem a trivial task in some cases, it’s just a waste of time and effort. Considering this and other idiosyncrasies tied to developing templates, I decided to leverage a “configure vs. customize” approach. Changes to a page template should be configured rather than customized. If page inheritance is used as the templating mechanism, the base page must be modified and recompiled to incorporate changes. This customization makes maintaining dynamic page templates an unnecessarily tedious task. Using a configurable approach, changes to a page’s template can be made in a configuration file which defines a page template declaratively. The Page Template FrameworkBased on this approach, I created the Page Template Framework. Figure 1 depicts the main components of the Page Template Framework. Figure 1 – The Page Template Framework As depicted in Figure 1, the Page Template Framework utilizes page inheritance to templates for use within a Web application. In order for a Web Form to utilize the Page Template Framework, it must inherit the The Page Template Framework defines page templates as a collection of User Controls to be added to a The following is a sample Page.config file: Listing A – Page.config <?xml version="1.0" encoding="utf-8"?>
<PageConfig>
<PageTemplates>
<PageTemplate Name="MainTemplate" IsDefault="true">
<Controls>
<Control Path="~/Controls/MainTemplate/Header.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/MainTemplate/Footer.ascx"
ControlPlacement="AfterContent" />
</Controls>
</PateTemplate>
<PageTemplate Name="DivisionTemplate">
<Controls>
<Control Path="~/Controls/DivisionTemplate/PagePre.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/DivisionTemplate/Header.ascx"
ControlPlacement="AfterContent" />
<Control Path="~/Controls/DivisionTemplate/Footer.ascx"
ControlPlacement="AfterContent" />
</Controls>
</PageTemplate>
</PageTemplates>
<Pages>
<Page Path="~/Default.aspx" TemplateName="MainTemplate" />
<Page Expression="^~/Templates/.*$" TemplateName="MainTemplate" />
</Pages>
</PageConfig>
As outlined in Listing A, the Page.config file consists of two sections: Additionally, a page template can be specified as the default template for Pages that are not listed in the In order for a Listing B – PageBase.cs – OnInit Method /// <summary>
/// Override the OnInit method of the Page class, and implement
/// the controls listed in the Page.config file
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
// Obtain the path to the Page.config file for the current application
string pageConfigPath = Server.MapPath(PageConfig.PageConfigFilePath);
// Check to see if the Page.config file exists
if (File.Exists(pageConfigPath))
{
// Check to see if the Page.config file has been loaded into Cache
if (Cache[PageConfig.PageConfigCacheKey] == null)
{
// Create a CacheDependency on the Page.config file
CacheDependency dependency = new
System.Web.Caching.CacheDependency(pageConfigPath);
// Load the Page.config file and insert the PageConfig into Cache
Cache.Insert(PageConfig.PageConfigCacheKey,
PageConfig.Load(pageConfigPath), dependency);
}
// Load the Page.config file into a PageConfig object
PageConfig pc = (PageConfig)Cache[PageConfig.PageConfigCacheKey];
// Get a reference to the current Page from the PageConfig
Page page = pc.FindPage(Request);
// Locate the PageTemplate for the current Page object
PageTemplate template = (page == null) ? pc.FindDefaultTemplate()
: pc.FindTemplate(page.TemplateName);
// Check to ensure a valid TemplateName attribute was specified
if (template != null)
{
// Declare a Control into which a template will be loaded
System.Web.UI.Control control = null;
// Iterate over the Controls in the template to locate
// the Controls with BeforeContent placement
for (int idx = 0; idx < template.Controls.Count; idx++)
{
// Check to see if the current Control has BeforeContent placement
if (((Control)template.Controls[idx]).ControlPlacement ==
ControlPlacement.BeforeContent)
{
// Load the specified Control from the Path specified in the PageConfig
control = this.LoadControl(((Control)template.Controls[idx]).Path);
// Check to see if the Control requires a unique name
if (((Control)template.Controls[idx]).UniqueName != null)
{
// Ensure that the value is not an Empty String
if (((Control)template.Controls[idx]).UniqueName != String.Empty)
{
// Set the ID property of the Control to the UniqueName attribute
control.ID = ((Control)template.Controls[idx]).UniqueName;
}
}
// Add the Contorl to the current Page
this.Controls.AddAt(idx, control);
}
}
// Initialize the Page content
base.OnInit(e);
// Iterate over the Controls in the template to locate
// the Controls with AfterContent placement
foreach (Control ctrl in template.Controls)
{
// Check to see if the current Control has AfterContent placement
if (ctrl.ControlPlacement == ControlPlacement.AfterContent)
{
// Load the specified Control from the Path specified in the PageConfig
control = this.LoadControl(ctrl.Path);
// Check to see if the Control requires a unique name
if (ctrl.UniqueName != null)
{
// Ensure that the value is not an Empty String
if (ctrl.UniqueName != String.Empty)
{
// Set the ID property of the Control to the UniqueName attribute
control.ID = ctrl.UniqueName;
}
}
// Load the specified Control and add it to the current Page
this.Controls.Add(control);
}
}
}
else
{
// Check to ensure that the Page as listed in the PageConfig
if (page != null)
{
// The page has an invalid TemplateName attribute, throw an exception
throw new Exception(
String.Format("Invalid TemplateName " +
"for Page /"{0}/". There is no" +
" template named /"{1}/".",
page.Path,
page.TemplateName));
}
else
{
// The pages was not listed in the PageConfig,
// so Initialize the Page content
base.OnInit(e);
}
}
}
else
{
// Initialize the Page content
base.OnInit(e);
}
}
As detailed in Listing B, the The Sample ApplicationThe sample application provided demonstrates the functionality of the Page Template Framework. The only Listing C – MainTemplate Page Template <PageTemplate Name="MainTemplate">
<Controls>
<Control Path="~/Controls/MainTemplate/Header.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/MainTemplate/ContentContainerPre.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/MainTemplate/NavigationContainerPre.ascx" />
ControlPlacement="BeforeContent"
<Control Path="~/Controls/General/Navigation.ascx"
ControlPlacement="BeforeContent"
UniqueName="GeneralNavigation" />
<Control Path="~/Controls/MainTemplate/NavigationContainerPost.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/MainTemplate/ContentContainerPost.ascx"
ControlPlacement="AfterContent" />
<Control Path="~/Controls/MainTemplate/Footer.ascx"
ControlPlacement="AfterContent" />
</Controls>
</PageTemplate>
Note the additional attribute on the fourth <CONTROL> element in Listing C. The Listing D – Programmatic Access to Controls // Find the General Navigation Control by it's UniqueName attribute
PageTemplateSample.Controls.General.Navigation nav =
(PageTemplateSample.Controls.General.Navigation)
this.FindControl("GeneralNavigation");
To test this functionality, change the Listing E – Changing a Page’s Template <Page Path="~/Default.aspx" TemplateName="DivisionTemplate" />
Not only will the content of Default.aspx appear within the Division page template, but the appearance of the Navigation.ascx User Control will change based on the programmatic access to the control, as outlined above. ConsiderationsThis framework was developed to provide functionality for creating page templates for use within ASP.NET 1.1 Web applications; therefore, it is important to note that there are some considerations to make when implementing the framework. In ASP.NET 2.0, Master Pages will provide design-time support for the content of Master Pages. The Page Template Framework does not provide design-time support for the content of the page templates; however, you can still use the Web Forms designer to create the content of a The Page Template Framework, by virtue of its design, provides a system for defining page templates to be implemented in a class derived from the Listing F – Page Template Inheritance <PageTemplate Name="MyTemplate">
<Controls>
<Control Path="~/Controls/Header.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/Footer.ascx"
ControlPlacement="AfterContent" />
</Controls>
</PageTemplate>
<PageTemplate Name="MyDetailTemplate" Inherits="MyTemplate">
<Controls>
<Control Path="~/Controls/ContentHeader.ascx"
ControlPlacement="BeforeContent" />
<Control Path="~/Controls/LocalNavigation.ascx"
ControlPlacement="AfterContent" />
</Controls>
</PageTemplate>
As depicted in Listing F, declarative page template inheritance would allow nested page templates. Child page templates would be processed by the framework in between its parent’s ConclusionAlthough it is likely that this framework will be rendered obsolete by the release of ASP.NET 2.0, it is still a good tool to use when developing Web applications that require a flexible user interface. It is also a good exercise for developers who are unfamiliar with developing template-based applications, and want to get more experience. AcknowledgementsThanks to Sean Jones for reviewing and providing input on this article. |
Page Template Framework for ASP.NET 1.1
最新推荐文章于 2024-07-15 18:18:21 发布