多个 ContentPlaceHolder 和默认内容 (VB)

作者 :斯科特·米切尔

下载 PDF

检查如何将多个内容位置持有者添加到母版页,以及如何在内容位置持有者中指定默认内容。

简介

在前面的教程中,我们研究了母版页如何使 ASP.NET 开发人员能够创建一致的网站范围布局。 母版页定义其所有内容页和可逐页自定义的区域通用的标记。 在上一教程中,我们创建了一个简单的母版页(Site.master)和两个内容页(Default.aspxAbout.aspx)。 我们的母版页由两个名为 ContentPlaceHolders head 组成 MainContent,分别位于元素和 Web 窗体中 <head> 。 虽然内容页各有两个内容控件,但我们只为对应于 MainContent的内容控件指定了标记。

如两个 ContentPlaceHolder 控件所 Site.master证明的那样,母版页可能包含多个 ContentPlaceHolders。 更重要的是,母版页可以为 ContentPlaceHolder 控件指定默认标记。 然后,内容页可以选择指定自己的标记或使用默认标记。 在本教程中,我们将了解如何在母版页中使用多个内容控件,以及如何在 ContentPlaceHolder 控件中定义默认标记。

步骤 1:将其他 ContentPlaceHolder 控件添加到母版页

许多网站设计包含屏幕上的多个区域,这些区域是逐页自定义的。 Site.master,我们在前面的教程中创建的母版页包含名为 Web 窗体 MainContent中的单个 ContentPlaceHolder。 具体而言,此 ContentPlaceHolder 位于元素中mainContent<div>

图 1 显示 Default.aspx 通过浏览器查看时。 以红色圆圈的区域是对应于 MainContent的页面特定标记。

圆圈区域显示当前可逐页自定义的区域

图 01:圆圈区域显示当前可逐页自定义的区域(单击可查看全尺寸图像

假设除了图 1 中显示的区域之外,我们还需要在“课程”和“新闻”部分下方的左侧列中添加特定于页面的项目。 为此,我们将另一个 ContentPlaceHolder 控件添加到母版页。 若要继续操作,请在 Visual Web 开发人员中打开 Site.master 母版页,然后在“新闻”部分之后将工具箱中的 ContentPlaceHolder 控件拖到设计器上。 将 ContentPlaceHolder 的 ID 设置为 LeftColumnContent

向母版页的左列添加 ContentPlaceHolder 控件

图 02:向母版页的左列添加 ContentPlaceHolder 控件(单击可查看全尺寸图像

将 ContentPlaceHolder 添加到LeftColumnContent母版页后,我们可以通过在设置为LeftColumnContent的页面上ContentPlaceHolderID包含内容控件来逐页定义此区域的内容。 我们在步骤 2 中检查此过程。

步骤 2:在内容页中为新 ContentPlaceHolder 定义内容

向网站添加新内容页时,Visual Web 开发人员会自动在所选母版页中的每个 ContentPlaceHolder 的页面中创建内容控件。 在步骤 1 中将 ContentPlaceHolder 添加到 LeftColumnContent 母版页后,新的 ASP.NET 页面现在将具有三个内容控件。

为了说明这一点,请将新内容页添加到绑定到Site.master母版页的MultipleContentPlaceHolders.aspx根目录。 Visual Web 开发人员使用以下声明性标记创建此页面:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="MultipleContentPlaceHolders.aspx.vb" Inherits="MultipleContentPlaceHolders" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="LeftColumnContent" Runat="Server">
</asp:Content>

在引用 MainContent ContentPlaceHolders (Content2) 的内容控件中输入一些内容。 接下来,将以下标记添加到 Content3 Content 控件(引用 LeftColumnContent ContentPlaceHolder):

<h3>Page-Specific Content</h3>
<ul>
 <li>This content is defined in the content page.</li>
 <li>The master page has two regions in the Web Form that are editable on a
 page-by-page basis.</li>
</ul>

添加此标记后,通过浏览器访问页面。 如图 3 所示,放置在内容控件中的 Content3 标记显示在“新闻”部分下方的左列中(用红色圆圈)。 放入 Content2 的标记显示在页面的右侧部分(蓝色圆圈)。

左列现在包括新闻部分下方的页面特定内容

图 03:左列现在包括新闻部分下方的页面特定内容(单击可查看全尺寸图像

在现有内容页中定义内容

创建新内容页会自动合并我们在步骤 1 中添加的 ContentPlaceHolder 控件。 但是,我们的两个现有内容页面 - About.aspxDefault.aspx - 没有 ContentPlaceHolder 的内容控件 LeftColumnContent 。 若要在这两个现有页面中指定此 ContentPlaceHolder 的内容,我们需要自行添加内容控件。

与大多数 ASP.NET Web 控件不同,Visual Web 开发人员工具箱不包含内容控件项。 我们可以将内容控件的声明性标记手动键入到“源”视图中,但更简单、更快速的方法是使用“设计”视图。 About.aspx打开页面并切换到“设计”视图。 如图 4 所示, LeftColumnContent ContentPlaceHolder 显示在设计视图中;如果鼠标悬停在设计视图中,则显示标题为:“LeftColumnContent(Master)。标题中包含“Master”表示此 ContentPlaceHolder 的页面中没有定义内容控件。 如果 ContentPlaceHolder 存在 ContentPlaceHolder 的内容控件,则 MainContent标题将读取:“ContentPlaceHolderID (自定义)。

若要添加 ContentPlaceHolder 的内容控件 LeftColumnContentAbout.aspx请展开 ContentPlaceHolder 的智能标记,然后单击“创建自定义内容”链接。

About.aspx的设计视图显示 LeftColumnContent ContentPlaceHolder

图 04:显示 LeftColumnContent ContentPlaceHolder 的设计视图About.aspx单击以查看全尺寸图像

单击“创建自定义内容”链接会在页面中生成必要的内容控件,并将其ContentPlaceHolderID属性设置为 ContentPlaceHolder。ID 例如,单击区域中About.aspxLeftColumnContent“创建自定义内容”链接会将以下声明性标记添加到页面:

<asp:Content ID="Content3" runat="server" 
 contentplaceholderid="LeftColumnContent">
 
</asp:Content>

省略内容控件

ASP.NET 不需要所有内容页都包含母版页中定义的每个 ContentPlaceHolder 的内容控件。 如果省略内容控件,ASP.NET 引擎将使用母版页的 ContentPlaceHolder 中定义的标记。 此标记称为 ContentPlaceHolder 的默认内容 ,在某些区域的内容在大多数页面中很常见的情况下非常有用,但需要为少量页面自定义。 步骤 3 将探索在母版页中指定默认内容。

目前,Default.aspx包含两个 Content 控件和 head MainContent ContentPlaceHolders;它没有内容控件。LeftColumnContent 因此,呈现 ContentPlaceHolder 的默认内容时Default.aspxLeftColumnContent使用。 由于尚未为此 ContentPlaceHolder 定义任何默认内容,因此净效果是没有为此区域发出任何标记。 若要验证此行为,请访问 Default.aspx 浏览器。 如图 5 所示,新闻部分下方的左列中没有发出任何标记。

LeftColumnContent ContentPlaceHolder 未呈现任何内容

图 05:ContentPlaceHolder 未呈现 LeftColumnContent 任何内容(单击可查看全尺寸图像

步骤 3:在母版页中指定默认内容

某些网站设计包括一个区域,其内容对于网站中的所有页面都是相同的,但有一两个例外。 请考虑支持用户帐户的网站。 此类网站需要登录页面,访问者可以输入其凭据以登录到网站。 为了加快登录过程,网站设计人员可能包括每个页面左上角的用户名和密码文本框,以允许用户登录,而无需显式访问登录页面。 虽然这些用户名和密码文本框在大多数页面中都很有用,但它们在登录页中是冗余的,该页已包含用户凭据的文本框。

若要实现此设计,可以在母版页的左上角创建 ContentPlaceHolder 控件。 需要在其左上角显示用户名和密码文本框的每个页面都将为此 ContentPlaceHolder 创建内容控件并添加必要的界面。 另一方面,登录页将省略为此 ContentPlaceHolder 添加内容控件,或者创建未定义标记的内容控件。 此方法的缺点是,我们必须记住将用户名和密码文本框添加到添加到网站的每个页面(登录页除外)。 这要求麻烦。 我们可能忘记将这些文本框添加到页面或两个或更糟的是,我们可能没有正确实现接口(也许只添加一个文本框而不是两个文本框)。

更好的解决方案是将用户名和密码文本框定义为 ContentPlaceHolder 的默认内容。 这样做后,我们只需在不显示用户名和密码文本框(例如登录页)的几个页面中重写此默认内容。 为了说明为 ContentPlaceHolder 控件指定默认内容,让我们实现刚刚讨论的方案。

注意

本教程的其余部分将更新我们的网站,以便在所有页面(但登录页)的左侧列中包括登录界面。 但是,本教程不会检查如何配置网站以支持用户帐户。 有关本主题的详细信息,请参阅我的 窗体身份验证、授权、用户帐户和角色 教程。

添加 ContentPlaceHolder 并指定其默认内容

Site.master打开母版页,并将以下标记添加到“标签”和“课程”部分之间的DateDisplay左侧列:

<asp:ContentPlaceHolder ID="QuickLoginUI" runat="server">
 <asp:Login ID="QuickLogin" runat="server" 
    TitleText="<h3>Sign In</h3>"
    FailureAction="RedirectToLoginPage">
 </asp:Login>
</asp:ContentPlaceHolder>

添加此标记后,母版页的设计视图应类似于图 6。

母版页包括登录控件

图 06:母版页包括登录控件(单击以查看全尺寸图像

此 ContentPlaceHolder QuickLoginUI具有一个登录 Web 控件作为其默认内容。 登录控件显示一个用户界面,提示用户输入用户名和密码以及登录按钮。 单击“登录”按钮时,登录控件会在内部针对成员身份 API 验证用户的凭据。 若要在实践中使用此登录控件,则需要将站点配置为使用成员身份。 本主题超出了本教程的范围;有关构建支持用户帐户的 Web 应用程序的详细信息,请参阅我的 表单身份验证、授权、用户帐户和角色 教程。

随时自定义登录控件的行为或外观。 我设置了它的两个属性: TitleTextFailureAction。 默认值 TitleText 为“登录”的属性值显示在控件用户界面顶部。 我已设置此属性,以便它将文本“登录”显示为 <h3> 元素。 该 FailureAction 属性指示如果用户的凭据无效,该怎么办。 它默认为一个值 Refresh,该值将用户保留在同一页上,并在登录控件中显示失败消息。 我已将其 RedirectToLoginPage更改为,如果凭据无效,则会将用户发送到登录页。 当用户尝试从其他页面登录时,我更喜欢将用户发送到登录页,但失败,因为登录页可以包含其他说明和选项,这些说明和选项不容易适应左列。 例如,登录页可能包含用于检索忘记的密码或创建新帐户的选项。

创建登录页并重写默认内容

完成母版页后,下一步是创建登录页。 将 ASP.NET 页添加到网站的根目录, Login.aspx并将其绑定到 Site.master 母版页。 这样做将创建一个页面,其中包含四个内容控件,一个用于定义 Site.master的每个 ContentPlaceHolders。

向内容控件添加登录控件 MainContent 。 同样,可以随意将任何内容添加到 LeftColumnContent 该区域。 但是,请确保将 ContentPlaceHolder 的内容控件 QuickLoginUI 留空。 这将确保登录控件不会显示在登录页的左列中。

定义区域的内容MainContentLeftColumnContent后,登录页的声明性标记应如下所示:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="Login.aspx.vb" Inherits="Login" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
 <h2>
 Sign In</h2>
 <p>
 <asp:Login ID="Login1" runat="server" TitleText="">
 </asp:Login>
 </p>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="QuickLoginUI" Runat="Server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="LeftColumnContent" Runat="Server">
 <h3>Sign In Tasks</h3>
 <ul>
 <li>Create a New Account</li>
 <li>Recover Forgotten Password</li>
 </ul>
 <p>TODO: Turn the above text into links...</p>
</asp:Content>

图 7 显示通过浏览器查看此页面。 由于此页面指定 ContentPlaceHolder 的内容控件 QuickLoginUI ,因此它将替代母版页中指定的默认内容。 净效果是母版页的设计视图(见图 6)中显示的登录控件未在此页中呈现。

登录页重新压缩 QuickLoginUI ContentPlaceHolder 的默认内容

图 07:登录页将重新压缩 QuickLoginUI ContentPlaceHolder 的默认内容(单击以查看全尺寸图像

在新页面中使用默认内容

我们希望在左侧列中显示除登录页以外的所有页面的 Login 控件。 为此,除登录页之外的所有内容页面都应省略 ContentPlaceHolder 的内容 QuickLoginUI 控件。 通过省略内容控件,将改用 ContentPlaceHolder 的默认内容。

我们现有的内容页 - Default.aspxAbout.aspxMultipleContentPlaceHolders.aspx - 不包括内容控件,因为它们是在将 ContentPlaceHolder 控件 QuickLoginUI 添加到母版页之前创建的。 因此,不需要更新这些现有页面。 但是,默认情况下,添加到网站的新页面包括 ContentPlaceHolder 的内容控件 QuickLoginUI 。 因此,每次添加新内容页时,我们必须记住删除这些内容控件(除非我们想要替代 ContentPlaceHolder 的默认内容,如登录页的情况)。

若要删除内容控件,可以从源视图手动删除其声明性标记,也可以从设计视图中从其智能标记中选择“默认到主控形状的内容”链接。 任一方法都会从页面中删除内容控件,并产生相同的净效果。

图 8 显示 Default.aspx 通过浏览器查看时。 回想一下,Default.aspx声明性标记中只指定了两个内容控件,一个用于head一个。MainContent 因此,将显示和 ContentPlaceHolders 的默认内容LeftColumnContentQuickLoginUI

显示 LeftColumnContent 和 QuickLoginUI ContentPlaceHolders 的默认内容

图 08:显示和 QuickLoginUI ContentPlaceHolders 的默认内容LeftColumnContent单击以查看全尺寸图像

总结

ASP.NET 母版页模型允许母版页中任意数量的 ContentPlaceHolders。 更重要的是,ContentPlaceHolders 包括默认内容,在这种情况下,内容页中没有相应的内容控件。 本教程介绍了如何在母版页中包含其他 ContentPlaceHolder 控件,以及如何在新的和现有的 ASP.NET 页中为这些新的 ContentPlaceHolder 定义内容控件。 我们还研究了在 ContentPlaceHolder 中指定默认内容,这在只有少数页面需要自定义特定区域中其他标准化内容的情况下非常有用。

在下一教程中,我们将更详细地探讨 head ContentPlaceHolder,了解如何以声明方式和编程方式在逐页定义标题、元标记和其他 HTML 标头。

快乐编程!

关于作者

斯科特·米切尔是多个 ASP/ASP.NET 书籍的作者,4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 3.5。 斯科特可以在他的博客上 mitchell@4GuysFromRolla.com 或通过他的博客联系 http://ScottOnWriting.NET

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Suchi Banerjee。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请把我扔一条线。mitchell@4GuysFromRolla.com