多个 ContentPlaceHolder 和默认内容 (VB)

作者 :Scott Mitchell

下载 PDF

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

简介

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

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

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

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

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

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

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

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

将 ContentPlaceHolder 控件添加到母版页的左列

图 02:将 ContentPlaceHolder 控件添加到母版页的左列 (单击以查看全尺寸图像)

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

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

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

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

<%@ 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) 的 Content 控件中输入一些内容。 接下来,将以下标记添加到 Content3 引用 LeftColumnContent ContentPlaceHolder) 的 Content 控件 (:

<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 标记显示在页面的右侧部分, (用蓝色) 圆圈。

左列现在包括新闻部分下方 Page-Specific 内容

图 03:左列现在在“新闻”部分下方包含 Page-Specific 内容 (单击以查看全尺寸图像)

定义现有内容页中的内容

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

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

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

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

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

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

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

省略内容控件

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

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

未为 LeftColumnContent ContentPlaceHolder 呈现任何内容

图 05:没有为 LeftColumnContent ContentPlaceHolder 呈现任何内容 (单击以查看全尺寸图像)

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

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

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

更好的解决方案是将用户名和密码文本框定义为 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 控件作为其默认内容。 Login 控件显示一个用户界面,该界面提示用户输入其用户名和密码以及“登录”按钮。 单击“登录”按钮后,登录控件会针对成员资格 API 在内部验证用户的凭据。 若要在实践中使用此登录控件,需要将站点配置为使用成员身份。 本主题超出了本教程的范围;有关构建支持用户帐户的 Web 应用程序的详细信息,请参阅我的 Forms 身份验证、授权、用户帐户和角色 教程。

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

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

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

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

定义 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 显示了通过浏览器查看时的此页面。 由于此页面为 QuickLoginUI ContentPlaceHolder 指定 Content 控件,因此它将替代母版页中指定的默认内容。 其净效果是母版页的“设计”视图中显示的 Login 控件 (见图 6) 未在此页中呈现。

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

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

在新页面中使用默认内容

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

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

若要删除“内容”控件,可以从“源”视图中手动删除其声明性标记,或者从“设计”视图中,从其智能标记中选择“默认为母版内容”链接。 这两种方法都从页面中删除 Content 控件,并产生相同的净效果。

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

显示 LeftColumnContent 和 QuickLoginUI ContentPlaceHolders 的默认内容

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

总结

ASP.NET 母版页模型允许在母版页中使用任意数量的 ContentPlaceHolder。 此外,ContentPlaceHolders 包括默认内容,在内容页中没有相应的 Content 控件时会发出该内容。 在本教程中,我们了解了如何在母版页中包含其他 ContentPlaceHolder 控件,以及如何在新的和现有的 ASP.NET 页面中为这些新的 ContentPlaceHolder 定义 Content 控件。 我们还了解了如何在 ContentPlaceHolder 中指定默认内容,这在仅少数页面需要自定义特定区域内的标准化内容的情况下非常有用。

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

编程愉快!

关于作者

Scott Mitchell 是多本 ASP/ASP.NET 书籍的作者,4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆自学 ASP.NET 在24小时内3.5。 可在 上或通过他的博客http://ScottOnWriting.NET联系 mitchell@4GuysFromRolla.com Scott。

特别感谢

本教程系列由许多有用的审阅者查看。 本教程的首席审阅者是 Suchi Banerjee。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com