介绍 ASP.NET 网页 - 创建一致的布局

作者 Tom FitzMacken

本教程介绍如何使用布局为使用 ASP.NET 网页 的网站上的页面创建一致的外观。 它假定你已通过删除 ASP.NET 网页 中的数据库数据完成了该系列。

学习内容:

什么是布局页面。

如何将布局页面与动态内容组合在一起。

如何将值传递给布局页。

关于布局

到目前为止,你已创建的页面都是完整的独立页面。 它们都属于同一站点,但它们没有任何通用元素或标准外观。

大多数网站具有一致的外观和布局。 例如,如果转到 Microsoft.com/web 网站并环顾四周,则会看到页面都遵循整体布局和视觉主题:

创建此布局的 低效 方法是在每个页面上分别定义页眉、导航栏和页脚。 每次都会复制相同的标记。 如果要更改某些内容 (例如更新页脚) ,则必须单独更改每个页面。

这就是 布局页面 的用处。 在 ASP.NET 网页 中,可以定义一个布局页面,为网站上的页面提供整体容器。 例如,布局页可以包含页眉、导航区域和页脚。 布局页包含一个占位符,main内容所在的位置。

然后,可以定义仅包含该页面的标记和代码的单个内容页。 内容页不必是完整的 HTML 页面;它们甚至不必具有 元素。 它们还有一行代码,告知 ASP.NET 要在其中显示内容的布局页面。 下图大致显示了此关系的工作原理:

当你看到它的运行情况时,这种交互很容易理解。 在本教程中,你将更改电影页面以使用布局。

添加布局页

首先创建一个布局页,该页面定义具有页眉、页脚和main内容区域的典型页面布局。 在 WebPagesMovies 网站中,添加名为 _Layout.cshtml 的 CSHTML 页。

前导下划线 ( _ ) 字符很重要。 如果页面名称以下划线开头,ASP.NET 不会直接将页面发送到浏览器。 此约定允许您定义网站所需的页面,但用户不应能够直接请求。

将页面中的内容替换为以下内容:

My Movie Site

@RenderBody()

如你所看到的,此标记只是 HTML,它使用

元素定义页面中的三个部分,以及一
个元素来保存这三个部分。 页脚包含一些 Razor 代码: @DateTime.Now.Year,它将呈现页面中该位置的当前年份。

请注意,有一个名为 Movies.css 的样式表的链接。 样式表是定义元素的物理布局详细信息的位置。 稍后你将创建它。

此 _Layout.cshtml 页中唯一不寻常的功能是 @Render.Body() 行。 这是当此布局与其他页面合并时内容将转到的占位符。

添加 .css 文件

定义实际排列 (即页面上元素的外观) 的首选方法是使用级联样式表 (CSS) 规则。 因此,你将创建一个 .css 文件,其中包含新布局的规则。

在 WebMatrix 中,选择站点的根。 然后在功能区的“ 文件 ”选项卡中,单击“ 新建 ”按钮下的箭头,然后单击“ 新建文件夹”。

将新文件夹命名 为 Styles。

在新的 Styles 文件夹中,创建名为 Movies.css 的文件。

将新的 .css 文件的内容替换为以下内容:

html{ height:100%; margin:0; padding:0; }

body {

height:60%;

font-family:'Trebuchet MS', 'Arial', 'Helvetica', 'sans-serif';

font-size:10pt;

background-color: LightGray;

line-height:1.6em;

}

h1{ font-size:1.6em; }

h2{ font-size:1.4em; }

#container{

min-height:100%;

position:relative;

left:10%;

}

#header{

padding:8px;

width:80%;

background-color:#4b6c9e;

color:White;

}

#main{

width:80%;

padding: 8px;

padding-bottom:4em;

background-color:White;

}

#footer{

width:80%;

height:2em;

padding:8px;

margin-top:-2em;

background-color:LightGray;

}

.head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }

.grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }

.alt { background-color: #E8E8E8; color: #000; }

.selected {background-color:Yellow;}

span.caption {width:100px;}

span.dataDisplay {font-weight:bold;}

我们不会对这些 CSS 规则说太多,只是要注意两点。 一个是,除了设置字体和大小外,规则还使用绝对定位来建立页眉、页脚和main内容区域的位置。 如果你不熟悉 CSS 中的定位,可以在 W3Schools 站点上阅读 CSS 定位 教程。

另一个需要注意的是,在底部,我们复制了最初在 Movies.cshtml 文件中单独定义的样式规则。

使用 ASP.NET 网页显示数据简介教程中使用了这些规则,使WebGrid帮助程序呈现向表中添加了条带的标记。 (如果要对样式定义使用 .css 文件,则不妨将整个网站的样式规则放在其中。)

更新电影文件以使用布局

现在,您可以更新网站中的现有文件以使用新布局。 打开 Movies.cshtml 文件。 在顶部,作为第一行代码,添加以下内容:

Layout = "~/_Layout.cshtml";

页面现在以这种方式开始:

@{

Layout = "~/_Layout.cshtml";

var db = Database.Open("WebPagesMovies") ;

var selectCommand = "SELECT * FROM Movies";

var searchTerm = "";

// Etc.

这一行代码告知 ASP.NET,当 “电影 ”页运行时,它应与 _Layout.cshtml 文件合并。

由于 Movies.cshtml 文件现在使用布局页,因此可以从由 _Layout.cshtml 文件负责的 Movies.cshtml 页中删除标记。 取出 、 和 开始和结束标记。 取出整个 元素及其内容,其中包括网格的样式规则,因为现在已在 .css 文件中获取这些规则。 使用时,将现有

元素更改为 元素

;布局页中已有一个

元素。 将

文本更改为“列出电影”。

通常,无需在内容页面中进行此类更改。 当您使用布局页面启动网站时,您将创建内容页面时,无需所有这些元素即可开始。 不过,在这种情况下,你要将独立页面转换为使用布局的页面,因此需要一些清理。

完成后, Movies.cshtml 页面将如下所示:

@{

Layout = "~/_Layout.cshtml";

var db = Database.Open("WebPagesMovies") ;

var selectCommand = "SELECT * FROM Movies";

var searchTerm = "";

if(!Request.QueryString["searchGenre"].IsEmpty() ) {

selectCommand = "SELECT * FROM Movies WHERE Genre = @0";

searchTerm = Request.QueryString["searchGenre"];

}

if(!Request.QueryString["searchTitle"].IsEmpty() ) {

selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";

searchTerm = "%" + Request.QueryString["searchTitle"] + "%";

}

var selectedData = db.Query(selectCommand, searchTerm);

var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);

}

List Movies

value="@Request.QueryString["searchGenre"]" />


(Leave blank to list all movies.)


@grid.GetHtml(

tableStyle: "grid",

headerStyle: "head",

alternatingRowStyle: "alt",

columns: grid.Columns(

grid.Column(format: @Edit),

grid.Column("Title"),

grid.Column("Genre"),

grid.Column("Year"),

grid.Column(format: @Delete)

)

)

Add a movie

测试布局

现在可以看到布局的外观。 在 WebMatrix 中,右键单击 Movies.cshtml 页,然后选择“ 在浏览器中启动”。 当浏览器显示页面时,页面如下所示:

ASP.NET 已将 Movies.cshtml 页面的内容合并到方法所在的RenderBody_Layout.cshtml 页中。 当然, _Layout.cshtml 页面引用定义页面外观的 .css 文件。

更新 AddMovie 页面以使用布局

布局的真正好处是,你可以将它们用于网站中的所有页面。 打开 AddMovie.cshtml 页。

你可能还记得 ,AddMovie.cshtml 页面最初包含一些 CSS 规则来定义验证错误消息的外观。 由于您现在拥有网站的 .css 文件,因此您可以将这些规则移动到 .css 文件。 从 AddMovie.cshtml 文件中删除它们,并将其添加到 Movies.css 文件的底部。 你正在移动以下规则:

.field-validation-error {

font-weight:bold;

color:red;

background-color:yellow;

}

.validation-summary-errors{

border:2px dashed red;

color:red;

background-color:yellow;

font-weight:bold;

margin:12px;

}

现在,在 AddMovie.cshtml 中执行与对 Movies.cshtml 所做的相同类型的更改 - 添加 Layout="~/_Layout.cshtml; 和删除现在无关的 HTML 标记。 将

元素更改为

。 完成后,页面将如以下示例所示:

@{

Layout = "~/_Layout.cshtml";

Validation.RequireField("title", "You must enter a title");

Validation.RequireField("genre", "Genre is required");

Validation.RequireField("year", "You haven't entered a year");

var title = "";

var genre = "";

var year = "";

if(IsPost){

if(Validation.IsValid()){

title = Request.Form["title"];

genre = Request.Form["genre"];

year = Request.Form["year"];

var db = Database.Open("WebPagesMovies");

var insertCommand =

"INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";

db.Execute(insertCommand, title, genre, year);

Response.Redirect("~/Movies");

}

}

}

Add a Movie

@Html.ValidationSummary()

Movie Information

@Html.ValidationMessage("title")

@Html.ValidationMessage("genre")

@Html.ValidationMessage("year")

运行页面。 现在如下图所示:

您希望对网站中的页面进行类似的更改- EditMovie.cshtml 和 DeleteMovie.cshtml。 但是,在执行此操作之前,你可以对布局进行另一次更改,使其更灵活一点。

将标题信息传递到布局页

创建的 _Layout.cshtml 页面有一个 设置为“我的电影网站”的 元素。 大多数浏览器将此元素的内容显示为选项卡上的文本:</p> <p>此游戏信息是通用的。 假设希望标题文本更特定于当前页。 (搜索引擎还使用标题文本来确定页面的内容。) 可以将内容页(如 Movies.cshtml 或 AddMovie.cshtml )中的信息传递到布局页,然后使用该信息自定义布局页面呈现的内容。</p> <p>再次打开 Movies.cshtml 页面。 在顶部的代码中,添加以下行:</p> <p>Page.Title = "List Movies";</p> <p>对象 Page 在所有 .cshtml 页面上可用,用于此目的,即在页面及其布局之间共享信息。</p> <p>打开 “_Layout.cshtml ”页。 更改 <title> 元素,使其类似于以下标记:</p> <p><title>@Page.Title

此代码在页面的该 Page.Title 位置的 属性中呈现任何信息。

运行 Movies.cshtml 页。 这一次,浏览器选项卡显示作为 的值 Page.Title传递的内容:

如果需要,请在浏览器中查看页面源。 可以看到 元素 呈现为 <title>List Movies

提示

Page 对象

的 Page 一个有用功能是它是动态对象 , Title 属性不是固定或保留名称。 可以将 任何 名称用于 对象的值 Page 。 例如,可以使用名为 Page.CurrentName 或 Page.MyPage的属性轻松传递标题。 唯一的限制是名称必须遵循可以命名的属性的常规规则。 (例如,名称不能包含 space.)

可以使用 对象传递任意数量的值 Page 。 如果要将电影信息传递到布局页,可以使用 和 Page.Genre 和 Page.MovieYear之类的Page.MovieTitle内容传递值。 (或你为存储信息而发明的任何其他名称。) 唯一的要求(可能很明显)是在内容页和布局页面中使用相同的名称。

使用 Page 对象传递的信息不仅限于要显示在布局页上的文本。 可以将值传递给布局页,然后布局页中的代码可以使用该值决定是否显示页面的某个部分、要使用的 .css 文件等。 在 对象中 Page 传递的值与在代码中使用的任何其他值类似。 只是值源自内容页,并传递到布局页。

打开 AddMovie.cshtml 页,并在代码顶部添加一行,为 AddMovie.cshtml 页面提供标题:

Page.Title = "Add a Movie";

运行 AddMovie.cshtml 页。 可看到新标题:

更新剩余页面以使用布局

现在,您可以完成网站中的剩余页面,以便它们使用新布局。 依次打开 EditMovie.cshtml 和 DeleteMovie.cshtml ,并在其中进行相同的更改。

添加链接到布局页的代码行:

Layout = "~/_Layout.cshtml";

添加一行以设置页面标题:

Page.Title = "Edit a Movie";

或:

Page.Title = "Delete a Movie";

删除所有无关的 HTML 标记 - 基本上,只保留元素内部 的位 (加上顶部) 的代码块。

元素更改为

元素。

进行这些更改后,请测试每个更改,并确保其正确显示且标题正确。

关于布局页面的分别想法

在本教程中,你创建了 一个 _Layout.cshtml 页面,并使用 RenderBody 方法合并了另一个页面中的内容。 这是在网页中使用布局的基本模式。

布局页面具有我们此处未介绍的其他功能。 例如,可以嵌套布局页 - 一个布局页可以依次引用另一个布局页。 如果使用需要不同布局的网站子部分,嵌套布局可能很有用。 还可以使用其他方法 (例如, RenderSection) 在布局页中设置命名节。

布局页面和 .css 文件的组合功能非常强大。 正如你将在下一个教程系列中看到的,在 WebMatrix 中,你可以基于模板创建一个网站,该 模板为你提供了一个具有预生成功能的网站。 模板充分利用布局页面和 CSS 来创建外观极佳且具有菜单等功能的网站。 下面是基于模板的网站主页的屏幕截图,其中显示了使用布局页面和 CSS 的功能:

电影页面的完整列表 (更新为使用布局页面)

@{

Layout = "~/_Layout.cshtml";

Page.Title = "List Movies";

var db = Database.Open("WebPagesMovies") ;

var selectCommand = "SELECT * FROM Movies";

var searchTerm = "";

if(!Request.QueryString["searchGenre"].IsEmpty() ) {

selectCommand = "SELECT * FROM Movies WHERE Genre = @0";

searchTerm = Request.QueryString["searchGenre"];

}

if(!Request.QueryString["searchTitle"].IsEmpty() ) {

selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";

searchTerm = "%" + Request.QueryString["searchTitle"] + "%";

}

var selectedData = db.Query(selectCommand, searchTerm);

var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);

}

List Movies


(Leave blank to list all movies.)


@grid.GetHtml(

tableStyle: "grid",

headerStyle: "head",

alternatingRowStyle: "alt",

columns: grid.Columns(

grid.Column(format: @Edit),

grid.Column("Title"),

grid.Column("Genre"),

grid.Column("Year"),

grid.Column(format: @Delete)

)

)

Add a movie

添加影片页面的完整页面列表 (更新布局)

@{

Layout = "~/_Layout.cshtml";

Page.Title = "Add a Movie";

Validation.RequireField("title", "You must enter a title");

Validation.RequireField("genre", "Genre is required");

Validation.RequireField("year", "You haven't entered a year");

var title = "";

var genre = "";

var year = "";

if(IsPost){

if(Validation.IsValid()){

title = Request.Form["title"];

genre = Request.Form["genre"];

year = Request.Form["year"];

var db = Database.Open("WebPagesMovies");

var insertCommand = "INSERT INTO Movies (Title, Genre, Year) VALUES(@0, @1, @2)";

db.Execute(insertCommand, title, genre, year);

Response.Redirect("~/Movies");

}

}

}

Add a Movie

@Html.ValidationSummary()

Movie Information

@Html.ValidationMessage("title")

@Html.ValidationMessage("genre")

@Html.ValidationMessage("year")

针对布局) 更新的“删除影片页面” (的完整页面列表

@{

Layout = "~/_Layout.cshtml";

Page.Title = "Delete a Movie";

var title = "";

var genre = "";

var year = "";

var movieId = "";

if(!IsPost){

if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].AsInt() > 0){

movieId = Request.QueryString["ID"];

var db = Database.Open("WebPagesMovies");

var dbCommand = "SELECT * FROM Movies WHERE ID = @0";

var row = db.QuerySingle(dbCommand, movieId);

if(row != null) {

title = row.Title;

genre = row.Genre;

year = row.Year;

}

else{

Validation.AddFormError("No movie was found for that ID.");

// If you are using a version of ASP.NET Web Pages 2 that's

// earlier than the RC release, comment out the preceding

// statement and uncomment the following one.

//ModelState.AddFormError("No movie was found for that ID.");

}

}

else{

Validation.AddFormError("No movie was found for that ID.");

// If you are using a version of ASP.NET Web Pages 2 that's

// earlier than the RC release, comment out the preceding

// statement and uncomment the following one.

//ModelState.AddFormError("No movie was found for that ID.");

}

}

if(IsPost && !Request["buttonDelete"].IsEmpty()){

movieId = Request.Form["movieId"];

var db = Database.Open("WebPagesMovies");

var deleteCommand = "DELETE FROM Movies WHERE ID = @0";

db.Execute(deleteCommand, movieId);

Response.Redirect("~/Movies");

}

}

Delete a Movie

@Html.ValidationSummary()

Return to movie listing

Movie Information

Title:

@title

Genre:

@genre

Year:

@year

“编辑影片页面”的完整页面列表 (更新布局)

@{

Layout = "~/_Layout.cshtml";

Page.Title = "Edit a Movie";

var title = "";

var genre = "";

var year = "";

var movieId = "";

if(!IsPost){

if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {

movieId = Request.QueryString["ID"];

var db = Database.Open("WebPagesMovies");

var dbCommand = "SELECT * FROM Movies WHERE ID = @0";

var row = db.QuerySingle(dbCommand, movieId);

if(row != null) {

title = row.Title;

genre = row.Genre;

year = row.Year;

}

else{

Validation.AddFormError("No movie was selected.");

// If you are using a version of ASP.NET Web Pages 2 that's

// earlier than the RC release, comment out the preceding

// statement and uncomment the following one.

//ModelState.AddFormError("No movie was selected.");

}

}

else{

Validation.AddFormError("No movie was selected.");

// If you are using a version of ASP.NET Web Pages 2 that's

// earlier than the RC release, comment out the preceding

// statement and uncomment the following one.

//ModelState.AddFormError("No movie was selected.");

}

}

if(IsPost){

Validation.RequireField("title", "You must enter a title");

Validation.RequireField("genre", "Genre is required");

Validation.RequireField("year", "You haven't entered a year");

Validation.RequireField("movieid", "No movie ID was submitted!");

title = Request.Form["title"];

genre = Request.Form["genre"];

year = Request.Form["year"];

movieId = Request.Form["movieId"];

if(Validation.IsValid()){

var db = Database.Open("WebPagesMovies");

var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";

db.Execute(updateCommand, title, genre, year, movieId);

Response.Redirect("~/Movies");

}

}

}

Edit a Movie

@Html.ValidationSummary()

Movie Information

Return to movie listing

即将上一步

在下一教程中,你将了解如何将网站发布到 Internet,以便每个人都可以看到它。

其他资源

创建一致的外观 — 一篇文章提供有关使用布局的更多详细信息。 它还介绍如何将值传递给显示或隐藏部分内容的布局页面。

使用 Razor 嵌套布局页面 — Mike Brind 博客中提供了有关如何嵌套布局页面的示例。 (包括 pages 的下载。)

上一页下一页

友情链接