母版页与网站导航3
简介
用户友好网站的一个共同特征是其具有一致的站点级页面布局和导航模式。 ASP.NET 2.0 引入了两种新功能,它们极大地简化了站点级页面布局和导航模式的实现过程。这两种功能是:母版页和网站导航。母版页允许开发人员创建具有指定的可编辑区域的站点级模板。随后,此模板可应用到网站中的 ASP.NET 页面上。这些 ASP.NET 页面只需为母版页中指定的可编辑区域提供相应内容 – 在使用母版页的所有 ASP.NET 页面中,母版页中的所有其它标记都相同。此模型允许开发人员定义并集中实现站点级页面布局。因此,开发人员可以方便地为所有页面创建一致的外观,并进行轻松的更新。
网站导航系统 为网页开发人员提供了定义站点地图的机制 , 同时还提供了API , 允许开发人员通过编程来查询该站点地图。使用新的导航 Web 控件( Menu 、 TreeView 和 SiteMapPath ),开发人员可以轻松地在普通的导航用户界面元素中呈现全部或部分站点地图。在本篇教程中,我们将使用默认的网站导航提供者,即,我们的站点地图将在 XML 格式的文件中定义。
为阐明这些概念并提高教程网站的可用性,在本篇教程中,我们将定义一个站点级页面布局,实现站点地图并添加导航 UI 。在本教程结束时,我们将拥有完善的网站设计方案来构建教程网页。
.png)
图1 :教程结束时完成的网站
步骤1 :创建母版页
第一个步骤是为该网站创建母版页。此时,我们的网站仅包含以下内容:Typed DataSet( Northwind.xsd ,位于 App_Code 文件夹中)、 BLL 类( App_Code 文件夹中的 ProductsBLL.cs 、 CategoriesBLL.cs 等)、数据库( NORTHWND.MDF ,位于 App_Data 文件夹中)、配置文件 (Web.config) 和一个 CSS 样式表文件 (Styles.css) 。我从前两篇教程中删除了使用 DAL 和 BLL 演示的页面和文件,因为我们还会在后面的教程中再次详细介绍这些示例。
.png)
图2 :此项目中的文件
要创建母版页,在Solution Explorer 中右键单击该项目的名称,选择 Add New Item 。然后,从模板列表中选择 Master Page 类型,将其命名为 Site.master 。
.png)
图3 :为网站添加一个新母版页
在此母版页中定义站点级页面布局。可以使用Design 视图添加所需的布局或 Web 控件,或者在Source 视图中手动添加标记。在我的母版页中,我利用 级联样式表 进行定位,并使用了在外部文件 Style.css 中定义的带有 CSS 设置的样式。通过定义 CSS 规则,导航 <div> 的内容按以下方式完全定位:在左侧显示,固定宽度为 200 像素。
Site.master
<%@ Master Language="C#" AutoEventWireup="true"
CodeFile="Site.master.cs" Inherits="Site" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Working with Data Tutorials</title>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
<form id="form1" runat="server">
<div id="header">
<span class="title">Working with Data Tutorials</span>
<span class="breadcrumb">
TODO: Breadcrumb will go here...</span>
</div>
<div id="content">
<asp:contentplaceholder id="MainContent"
runat="server">
<!-- Page-specific content will go here... -->
</asp:contentplaceholder>
</div>
<div id="navigation">
TODO: Menu will go here...
</div>
</form>
</div>
</body>
</html>
母版页定义的内容包括固定的页面布局,以及使用该母版页的 ASP.NET 页面的可编辑的区域。你可以通过 ContentPlaceHolder 控件指出这些内容可编辑的区域,并在 <div> 内容中查看。我们的母版页只有一个 ContentPlaceHolder (MainContent) ,但在通常情况下,母版页可以有许多 ContentPlaceHolders 。
使用前面输入的标记,切换到显示母版页布局的 Design 视图。使用此母版页的所有 ASP.NET 页面都将显示如下的统一布局,而指定的MainContent区域则是每个页面不同的区域。
.png)
图4 :通过 Design 视图查看的母版页
步骤2 :为网站添加主页
定义完母版页后,我们将向网站添加 ASP.NET 页面。首先要添加的是 Default.aspx ,即网站的主页。在 Solution Explorer 中右键单击项目名称,选择 Add New Item 。从模板列表中选择 Web Form 选项,并为 Default.aspx 文件命名。同时,选中 "Select master page" 复选框。
.png)
图5 :添加一个新 Web 窗体并选中 “Select master page” 复选框
单击OK 按钮后,系统要求我们选择此 ASP.NET 新页面应使用的母版页。你的项目中可以有多个母版页,但我们的项目只有一个。
.png)
图6 :选择此 ASP.NET 页面应使用的母版页
选择母版页后,新的ASP.NET 页面将包含以下标记 :
Default.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
Runat="Server">
</asp:Content>
@Page 指令中引用了所用的母版页文件(MasterPageFile="~/Site.master") , 并且 ASP.NET 页面的标记中 定义了Content 控件对应母版页中定义的每个ContentPlaceHolder 控件,该控件的ContentPlaceHolderID 将Content 控件映射到特定的ContentPlaceHolder 。在 Content 控件中,你可以放置希望在相应的 ContentPlaceHolder 中显示的标记。将 @Page 指令的 Title 属性设置为 Home ,并向 Content 控件添加一些欢迎词。
Default.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" Title="Home" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
Runat="Server">
<h1>Welcome to the Working with Data Tutorial Site</h1>
<p>This site is being built as part of a set of tutorials that
illustrate some of the new data access and databinding features in
ASP.NET 2.0 and Visual Web Developer.</p>
<p>Over time, it will include a host of samples that
demonstrate:</p>
<ul>
<li>Building a DAL (data access layer),</li>
<li>Using strongly typed TableAdapters and DataTables</li>
<li>Master-Detail reports</li>
<li>Filtering</li>
<li>Paging,</li>
<li>Two-way databinding,</li>
<li>Editing,</li>
<li>Deleting,</li>
<li>Inserting,</li>
<li>Hierarchical data browsing,</li>
<li>Hierarchical drill-down,</li>
<li>Optimistic concurrency,</li>
<li>And more!</li>
</ul>
</asp:Content>
即使已经在母版页中定义了 <title> 元素,我们也可以在 ASP.NET 页面中使用 @Page 指令中的 Title 属性设置页面的标题。我们还可以使用 Page.Title 通过编程设置标题。注意,母版页对样式表(如 Style.css )的引用自动更新,因此,无论 ASP.NET 页面所在目录相对于母版页的位置如何,样式表都可以在所有 ASP.NET 页面中运行。
切换到Design 视图,我们可以看到页面在浏览器中是如何显示的。注意,在 ASP.NET 页面的 Design 视图中,只有内容可编辑区域可以编辑,除母版页中定义的 ContentPlaceHolder 标记外,其它标记都显示为灰色。
.png)
图7 :ASP.NET 页面的 Design 视图显示可编辑和不可编辑区域
当通过浏览器访问 Default.aspx 页面时,ASP.NET 引擎自动合并该页面的母版页内容和 ASP.NET 内容。最后在 HTML 中呈现合并后的内容,并将 HTML 内容发送到发出请求的浏览器。下一次访问主页时,如果母版页的内容已更新,所有使用该母版页的 ASP.NET 页面会重新将其内容与新的母版页内容合并。简而言之,母版页模型允许定义一个页面布局模板(母版页),该模板的变化会立即体现在整个网站中。
为网站添加其它 ASP.NET 页面
下面,我们会为网站添加其它 ASP.NET 页面数据,这些页面最终将用于演示各种报表的Demo。由于Demo的总数超过 35 个,因此我们只创建前几个(而不是所有)页面。此外,由于存在很多类别的Demo,为了更好地管理Demo,我们将为这些类别添加文件夹。现在,添加以下三个文件夹:
- BasicReporting
- Filtering
- CustomFormatting
最后,根据图8 所示 Solution Explorer 中的内容添加新文件。在添加每个文件时,记住选中"Select master page" 复选框。
.png)
图8 : 添加以下文件
步骤2 :创建站点地图
在管理由多个页面组成的网站时,其中一项挑战是为访问者提供一个便捷的方法在网站中导航。首先,必须定义网站的导航结构。然后,将此结构转换为可导航的用户界面元素,如菜单或 breadcrumb 。最后,我们需要维护整个过程,并在网站添加和删除页面时更新此过程。在出现 ASP.NET 2.0 之前,开发人员需要自己创建和维护网站的导航结构,并手动将导航结构转换为可导航的用户界面元素。然而,使用 ASP.NET 2.0 ,开发人员可以利用非常灵活的内置网站导航系统。
使用ASP.NET 2.0 网站导航系统,开发人员能够定义站点地图,并可以在随后通过可编程的 API 访问这些信息。 ASP.NET 包含了 一个站点地图提供者,希望以 XML 文件格式存储站点地图数据。但是,由于网站导航系统在 提供者模型 上构建,我们可以扩展该系统,允许其支持使站点地图信息序列化的其它方式。 Jeff Prosise 的文章 The SQL Site Map Provider You've Been Waiting For显示了如何创建站点地图提供程序,将站点地图存储在 SQL Server 数据库中;另一个选择是创建基于文件系统结构的站点地图提供 者
然而,在本篇教程中,我们将使用ASP.NET 2.0 包含的默认站点地图提供程序。要创建站点地图,在 Solution Explorer 中右键单击项目的名称,选择 Add New Item ,然后选择 Site Map 选项。命名为 Web.sitemap ,单击 Add 按钮。
.png)
图9 :为项目添加站点地图
站点地图文件是 XML 文件。注意, Visual Studio 为站点地图结构提供 IntelliSense 。站点地图文件必须使用 <siteMap> 节点作为根节点,此根节点必须包含且仅包含一个 <siteMapNode> 子元素。而该 <siteMapNode> 子元素可以包含任意数量的 <siteMapNode> 派生元素。
定义站点地图来模拟文件系统结构。即,为上述三个文件夹中的每一个添加一个<siteMapNode> 元素,然后为这些文件夹中的所有 ASP.NET 页面添加 <siteMapNode> 子元素,如下所示 :
Web.sitemap
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="Home" description="Home">
<siteMapNode title="Basic Reporting"
url="~/BasicReporting/Default.aspx"
description="Basic Reporting Samples">
<siteMapNode url="~/BasicReporting/SimpleDisplay.aspx"
title="Simple Display"
description="Displays the complete contents
of a database table." />
<siteMapNode url="~/BasicReporting/DeclarativeParams.aspx"
title="Declarative Parameters"
description="Displays a subset of the contents
of a database table using parameters." />
<siteMapNode url="~/BasicReporting/ProgrammaticParams.aspx"
title="Setting Parameter Values"
description="Shows how to set parameter values
programmatically." />
</siteMapNode>
<siteMapNode title="Filtering Reports"
url="~/Filtering/Default.aspx"
description="Samples of Reports that Support Filtering">
<siteMapNode url="~/Filtering/FilterByDropDownList.aspx"
title="Filter by Drop-Down List"
description="Filter results using a drop-down list." />
<siteMapNode url="~/Filtering/MasterDetailsDetails.aspx"
title="Master-Details-Details"
description="Filter results two levels down." />
<siteMapNode url="~/Filtering/DetailsBySelecting.aspx"
title="Details of Selected Row"
description="Show detail results for a selected item in a GridView." />
</siteMapNode>
<siteMapNode title="Customized Formatting"
url="~/CustomFormatting/Default.aspx"
description="Samples of Reports Whose Formats are Customized">
<siteMapNode url="~/CustomFormatting/CustomColors.aspx"
title="Format Colors"
description="Format the grid's colors based
on the underlying data." />
<siteMapNode
url="~/CustomFormatting/GridViewTemplateField.aspx"
title="Custom Content in a GridView"
description="Shows using the TemplateField to
customize the contents of a field in a GridView." />
<siteMapNode
url="~/CustomFormatting/DetailsViewTemplateField.aspx"
title="Custom Content in a DetailsView"
description="Shows using the TemplateField to customize
the contents of a field in a DetailsView." />
<siteMapNode url="~/CustomFormatting/FormView.aspx"
title="Custom Content in a FormView"
description="Illustrates using a FormView for a
highly customized view." />
<siteMapNode url="~/CustomFormatting/SummaryDataInFooter.aspx"
title="Summary Data in Footer"
description="Display summary data in the grids footer." />
</siteMapNode>
</siteMapNode>
</siteMap>
站点地图定义网站的导航结构,该结构为层次结构,用于描述网站的各个部分。 Web.sitemap 中的每个 <siteMapNode> 元素代表网站导航结构中的一个部分。
.png)
图10 :站点地图用于表示分层的导航结构
ASP.NET 通过 .NET Framework 的 SiteMap 类 显示站点地图的结构。该类的 CurrentNode 属性能够返回用户当前访问区域的相关信息;而 RootNode 属性能够返回站点地图的根节点( 在我们的站点地图中 , 根节点为Home )。CurrentNode 与 RootNode 属性都会返回 SiteMapNode 实例,这些实例含有的属性包括 ParentNode 、 ChildNodes 、 NextSibling 、 PreviousSibling 等,这些属性允许用户遍历站点地图层次结构。
步骤 3:根据站点地图显示菜单
ASP.NET 2.0 中的数据访问可以通过编码实现 ( 与 ASP.NET 1.x 版本类似 ), 也可以通过新的 数据源控件 以声明方式实现。这些内置的数据源控件包括 SqlDataSource 控件(用于访问关系数据库数据)和 ObjectDataSource 控件(用于访问各个类的数据)等等。用户甚至可以创建自己的 自定义数据源控件 。
数据源控件用作 ASP.NET 页面与底层数据间的代理。为显示数据源控件获得的数据,通常,我们会再为页面添加一个 Web 控件,并将该控件绑定到数据源控件。要将一个 Web 控件绑定到数据源控件,只需将 Web 控件的 DataSourceID 属性设为数据源控件 ID 属性的值。
为简化站点地图数据的使用,ASP.NET 中包含了 SiteMapDataSource 控件, 该控件允许我们将 Web 控件绑定到网站的映射。 TreeView 和 Menu 这两个 Web 控件通常用于提供导航用户界面。要将站点地图数据绑定到 TreeView (或 Menu )控件,只需将一个 SiteMapDataSource 与 TreeView (或 Menu )控件一起添加到页面,系统会对 TreeView (或 Menu )控件的 DataSourceID 属性进行相应的设置。例如,我们可以使用以下标记将一个 Menu 控件添加到母版页:
<div id="navigation">
<asp:Menu ID="Menu1" runat="server"
DataSourceID="SiteMapDataSource1">
</asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
</div>
为了界面的美化,我们可以将SiteMapDataSource 控件绑定到Repeater 控件 , 如下所示 :
<div id="navigation">
<ul>
<li><asp:HyperLink runat="server" ID="lnkHome"
NavigateUrl="~/Default.aspx">Home</asp:HyperLink></li>
<asp:Repeater runat="server" ID="menu"
DataSourceID="SiteMapDataSource1">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%# Eval("Url") %>'>
<%# Eval("Title") %></asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
<asp:SiteMapDataSource ID="SiteMapDataSource1"
runat="server" ShowStartingNode="false" />
</div>
SiteMapDataSource 控件每次返回一级站点的地图层次结构,首先是站点地图的根节点 ( 在我们的站点地图中是 Home ),然后是下一个级别(Basic Reporting 、Filtering Reports 和Customized Formatting ),以此类推。在将 SiteMapDataSource 与 Repeater 绑定时,它会枚举返回的第一个级别,并将该级别中每个 SiteMapNode 实例 映射到 ItemTemplate 实例。要访问 SiteMapNode 的一个特定属性,我们可以使用 Eval(propertyName) 来获得每个 SiteMapNode 的 Url 和 Title 属性,以便进行超链接控制。
上述 Repeater 示例将呈现以下标记 :
<li>
<a href="/Code/BasicReporting/Default.aspx">Basic Reporting</a>
</li>
<li>
<a href="/Code/Filtering/Default.aspx">Filtering Reports</a>
</li>
<li>
<a href="/Code/CustomFormatting/Default.aspx">
Customized Formatting</a>
</li>
这些站点地图节点 (Basic Reporting 、Filtering Reports 和Customized Formatting ) 呈现的是站点地图的第二个 ( 而非第一个 ) 级别。这是因为, SiteMapDataSource 的 ShowStartingNode 属性设置为 False ,导致 SiteMapDataSource 绕过站点地图的根节点,转而开始返回第二个级别的站点地图层次结构。
要显示 Basic Reporting 、Filtering Reports 和 Customized Formatting SiteMapNodes 的子节点,我们可以为初始Repeater 的 ItemTemplate 添加另一个 Repeater 控件 。第二个 Repeater 控件 将绑定到 SiteMapNode 实例的 ChildNodes 属性,如下所示:
<asp:Repeater runat="server" ID="menu" DataSourceID="SiteMapDataSource1">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%# Eval("Url") %>'>
<%# Eval("Title") %></asp:HyperLink>
<asp:Repeater runat="server"
DataSource='<%# ((SiteMapNode) Container.DataItem).ChildNodes %>'>
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%# Eval("Url") %>'>
<%# Eval("Title") %></asp:HyperLink>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
</asp:Repeater>
这两个Repeater 导致系统显示以下标记( 为了体现简洁性 , 我们删除了一些标记 ):
<li>
<a href="/Code/BasicReporting/Default.aspx">Basic Reporting</a>
<ul>
<li>
<a href="/Code/BasicReporting/SimpleDisplay.aspx">
Simple Display</a>
</li>
<li>
<a href="/Code/BasicReporting/DeclarativeParams.aspx">
Declarative Parameters</a>
</li>
<li>
<a href="/Code/BasicReporting/ProgrammaticParams.aspx">
Setting Parameter Values</a>
</li>
</ul>
</li>
<li>
<a href="/Code/Filtering/Default.aspx">Filtering Reports</a>
...
</li>
<li>
<a href="/Code/CustomFormatting/Default.aspx">
Customized Formatting</a>
...
</li>
通过使用从 The CSS Anthology: 101 Essential Tips, Tricks, & Hacks ( 作者 : Rachel Andrew )中选择的 CSS 样式,<ul> 和 <li> 元素经过样式化,因此标记将产生以下可视化输出 :
.png)
图11 :由两个 Repeater 和一些 CSS 构成的菜单
此菜单位于母版页中,并绑定到在Web.sitemap 中定义的站点地图,即,站点地图的任何更改会立即反应到使用Site.master 母版页的所有页面。
禁用ViewState
所有ASP.NET 控件都可以选择将其状态保存到 视图状态 ,此视图状态在呈现的HTML 中序列化为隐藏的表单域。控件可以使用视图状态记住在页面返回时通过编程更改的状态,如绑定到一个数据 Web 控件的数据。当视图状态允许控件记住页面返回时的信息时,它将增加向客户端发送的标记的大小。如果没有进行严密监控,这将导致严重的页面膨胀。数据 Web 控件(尤其是 GridView )会向页面增加大量额外标记。当然,这些数据增加可能对宽带用户或企业内部网用户影响不大,但视图状态会给拨号上网的用户增加几秒钟的延迟时间。
要观察视图状态的影响,在浏览器中打开一个页面,然后查看网页发送的源代码( 在Internet Explorer 中,单击 View 菜单,选择 Source 选项 )。你还可以打开 页面跟踪 选项,查看该页面上每个控件的视图状态配置。视图状态信息经序列化后存放在名为 __VIEWSTATE 的隐藏表单域中,该字段位于 <form> 开始标记后的 <div> 元素中。仅当使用 Web 窗体时,视图状态才可以被保存;如果 ASP.NET 页面的声明语法中不包含 <form runat="server"> ,呈现的标记中不会出现 __VIEWSTATE 隐藏表单字段。
母版页生成的__VIEWSTATE 表单域会向页面生成的标记添加大约 1,800 个字节。这些额外的数据增加主要是 SiteMapDataSource 控件的内容保存到视图状态时由 Repeater 控件产生的。尽管 1,800 个字节看起来并不多,但当使用带有多个字段和记录的 GridView 时,视图状态很容易膨胀 10 倍或更多。
通过将EnableViewState 属性设置为 false ,用户可以在页面或控件级禁用视图属性,从而减小所呈现标记的大小。由于数据 Web 控件的视图状态可以保存页面返回绑定到数据 Web 控件的数据,在禁用数据 Web 控件的视图状态时,必须在每次页面返回时重新绑定数据。在 ASP.NET 1.x 版本中,这个责任落在页面开发人员身上;然而,在 ASP.NET 2.0 中,页面返回时,数据 Web 控件会在需要时重新绑定到数据源控件。
要减少页面的视图状态,我们可以将 Repeater 控件的 EnableViewState 属性设为 false 。此操作可以在设计器的 Properties 窗口中完成,也可以在 Source 视图中以声明方式完成。完成此修改后,Repeater 的声明标记应显示为:
<asp:Repeater runat="server" ID="menu" DataSourceID="SiteMapDataSource1"
EnableViewState="False">
<ItemTemplate>
... <i>ItemTemplate contents omitted for brevity</i> ...
</ItemTemplate>
</asp:Repeater>
经过此修改后,该页面所呈现的视图状态的大小缩减到52 个字节,减少了 97% 的视图状态数据!在该系列的教程中,我们会关闭数据 Web 控件的视图状态,以便减少所呈现标记的大小。在大多数示例中,在没有提示的情况下, EnableViewState 属性将设置为 false 。只有当数据 Web 控件必须启用视图状态才能提供所期望的功能时,我们才会讨论视图状态。
步骤4 :添加 Breadcrumb 导航
为完成母版页,我们需要为每个页面添加一个 breadcrumb 导航 UI 元素。Breadcrumb 导航会快速显示用户当前在网站层次结构中的位置。在 ASP.NET 2.0 中添加 breadcrumb 很简单,仅需向页面添加一个 SiteMapPath 控件;无需编码。
在我们的网站中,将此控件添加到头部的 <div> :
<span class="breadcrumb">
<asp:SiteMapPath ID="SiteMapPath1" runat="server">
</asp:SiteMapPath>
</span>
Breadcrumb 显示用户在站点地图层次结构中访问的当前页面,以及站点地图节点的 “ 上级节点 ”,直至根节点( 在我们的站点地图中是 Home )。
.png)
图12 :Breadcrumb 显示在站点地图层次结构中的当前页及其上层节点
步骤5 :为每个部分添加默认页面
在我们的网站中,教程细分为Basic Reporting 、Filtering 、Custom Formatting 等分类,每个分类拥有一个文件夹,该文件夹中有对应课程的 ASP.NET 页面。此外,每个文件夹中还包含一个 Default.aspx 页面。此默认页面将显示当前部分的所有教程。例如,在 BasicReporting 文件夹的 Default.aspx 中,我们可以链接到 SimpleDisplay.aspx 、 DeclarativeParams.aspx 和 ProgrammaticParams.aspx 。在此处,我们可以再次使用 SiteMap 类和数据 Web 控件显示 Web.sitemap 中定义的站点地图的信息。
让我们再次使用 Repeater 显示一个无序列表,但这一次,我们会显示教程的标题和说明。由于我们需要在每个 Default.aspx 页面重复完成此操作需要的标记和代码,因此我们可以将此 UI 逻辑封装成一个 用户控件 。在网站中创建一个名为 UserControls 的文件夹,在其中添加一种类型为 Web 用户控件的新条目,条目名为 SectionLevelTutorialListing.ascx ,包含以下标记:
.png)
图13 :向 UserControls 文件夹添加新 Web 用户控件Folder
SectionLevelTutorialListing.ascx
<%@ Control Language="CS" AutoEventWireup="true"
CodeFile="SectionLevelTutorialListing.ascx.cs"
Inherits="UserControls_SectionLevelTutorialListing" %>
<asp:Repeater ID="TutorialList" runat="server" EnableViewState="False">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li><asp:HyperLink runat="server"
NavigateUrl='<%# Eval("Url") %>'
Text='<%# Eval("Title") %>'></asp:HyperLink>
- <%# Eval("Description") %></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
SectionLevelTutorialListing.ascx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
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;
public partial class UserControls_SectionLevelTutorialListing : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
// If SiteMap.CurrentNode is not null,
// bind CurrentNode ChildNodes to the GridView
if (SiteMap.CurrentNode != null)
{
TutorialList.DataSource = SiteMap.CurrentNode.ChildNodes;
TutorialList.DataBind();
}
}
}
在前面的Repeater 示例中,我们以声明方式将 SiteMap 数据绑定到 Repeater ;然而,在此 SectionLevelTutorialListing 用户控件示例中,我们通过编程方式实现。在 Page_Load 事件处理程序中,将通过检测确保该页面的 URL 映射到站点地图中的一个节点。如果使用此用户控件的页面没有对应的 <siteMapNode> 条目, SiteMap.CurrentNode 将返回空值,没有数据绑定到 Repeater 。假设存在一个 CurrentNode ,我们将其子节点集绑定到 Repeater 。由于我们已经建立了站点地图,因此每个部分中的 Default.aspx 页面是该部分中所有教程的父节点,此节点将显示该部分所有教程的链接与说明,如下方屏幕截图所示。
一旦此Repeater 完成创建后,打开每个文件夹中的 Default.aspx 页面,转至 Design 视图,并将用户控件从 Solution Explorer 拖放到希望教程列表在其中显示的 Design 界面。
.png)
图14 :已将用户控件添加到 Default.aspx
.png)
图15 :Basic Reporting 教程列表
小结
完成站点地图和母版页后,现在,我们的数据相关教程拥有了一致的页面布局和导航模式。无论我们为网站添加了多少个页面,由于站点级页面布局与网站导航信息是集中管理的,因此更新这些信息是一个轻松快捷的过程。具体来说,在本教程中,页面布局信息和站点地图分别在 Site.master 母版页和 Web.sitemap 中定义。我们无需编写任何 代码就获得了站点级页面布局与导航机制。此外,我们仍在 Visual Studio 中提供完整的 WYSIWYG 设计器支持。
我们已经完成了数据访问层与业务逻辑层,并且定义了一致的页面布局和网站导航模式,接下来,我们将开始探讨常用报表模式。在接下来的三篇教程中,我们将讨论基本报表任务:在 GridView 、DetailsView 和 FormView 控件中显示从 BLL 获得的数据。
快乐编程!

浙公网安备 33010602011771号