学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

一、列表页面。

 我们首先来了解一下书籍列表页面,这个页面位置在 Pages/Books/Index.cshtml.cs :

复制代码
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Mvc.RazorPages; 
using Microsoft.EntityFrameworkCore; 
using RazorMvcBooks.Models; 
namespace RazorMvcBooks.Pages.Books
{ 
 public class IndexModel : PageModel
    { 
 private readonly RazorMvcBooks.Models.BookContext _context; 
 public IndexModel(RazorMvcBooks.Models.BookContext context)
        {
            _context = context;
        } 
 public IList<Book> Book { get;set; } 
 public async Task OnGetAsync()
        {
            Book = await _context.Book.ToListAsync();
        }
    }
}
复制代码

列表页面IndexModel派生自 PageModel。 按照命名规则PageModel 的派生类一般命名为 <PageName>Model。 构造函数使用依赖关系注入的方式将 BookContext 添加到页面。 所有通过上一文章中的方法创建的模板页面都是如此。

当Index页面发出请求时,OnGetAsync 方法向 Razor 页面返回一个书籍列表。 在 Razor 页面上调用 OnGetAsync 方法或 OnGet方法初始化页面数据。 在本示例中,OnGetAsync 将数据库中Book表中的所有书籍信息,并以列表的形式显示出来。

当 OnGet 方法返回 void 或 OnGetAsync方法返回 Task 时,不需要任何返回语句。 当返回类型是 IActionResult 或 Task<IActionResult> 时,必须提供返回语句。

下面我们介绍一下有返回的方法,例如 Pages/Movies/Create.cshtml.cs 页面中的OnPostAsync方法,代码如下:

复制代码
  public async Task<IActionResult> OnPostAsync()
        { 
 if (!ModelState.IsValid)
            { 
 return Page();
            }
 
            _context.Book.Add(Book); 
 await _context.SaveChangesAsync(); 
 return RedirectToPage("./Index");
        }
复制代码

其次, 我们来看看书籍列表页面中的前端代码,这个页面位置在 Pages/Books/Index.cshtml,在Visual Studio  2017中使用鼠标左键双击打开 页面,代码如下:

复制代码
@page
@model RazorMvcBooks.Pages.Books.IndexModel

@{
    ViewData["Title"] = "Index";
} 
<h2>Index</h2> 
<p> 
<a asp-page="Create">Create New</a> 
</p> 
<table class="table"> 
<thead> 
<tr> 
<th> 
@Html.DisplayNameFor(model => model.Book[0].Name) 
</th> 
<th> 
@Html.DisplayNameFor(model => model.Book[0].ReleaseDate) 
</th> 
<th> 
@Html.DisplayNameFor(model => model.Book[0].Author) 
</th> 
<th> 
@Html.DisplayNameFor(model => model.Book[0].Price) 
</th> 
<th>
</th> 
</tr> 
</thead> 
<tbody> 
@foreach (var item in Model.Book) { 
<tr> 
<td> 
@Html.DisplayFor(modelItem => item.Name) 
</td> 
<td> 
@Html.DisplayFor(modelItem => item.ReleaseDate) 
</td> 
<td> 
@Html.DisplayFor(modelItem => item.Author) 
</td> 
<td> 
@Html.DisplayFor(modelItem => item.Price) 
</td> <td> <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> | 
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> | 
<a asp-page="./Delete" asp-route-id="@item.ID">Delete
</a> 
</td> 
</tr> 
} 
</tbody> 
</table>
复制代码

Razor指令可以根据规则从 HTML 转换为 C# 或 Razor 特定标记。 当在 @ 符号后跟 Razor 保留关键字时,它会转换为 Razor 特定标记,如果不是Razor保留关键字,则会转换为 C#。

@page Razor 指令将文件转换为一个 MVC 操作,这意味着它可以处理请求。 @page 必须是页面上的第一个 Razor 指令。 @page 是转换成 Razor 特定标记的一个示例。

请查看下列HTML助手中使用的lambda表达式: 

   @Html.DisplayNameFor(model => model.Book[0].Name)

DisplayNameFor HTML辅助助手检查 Lambda 表达式中引用的Name属性来确定显示名称。 Lambda表达式是检查而不是求值。 这意味着当 model、model.Book 或 model.Book[0] 为 null 或为空时,不会存在任何访问冲突。 当使用Html辅助助手取值辅助方法对 Lambda 表达式取值(例如,使用 @Html.DisplayFor(modelItem => item.Title)),将取得该实体的属性值。

@model指令

@page
@model RazorMvcBooks.Pages.Books.IndexModel

@model 指令指定传递给 Razor 页面的实体类型。在上面的示例中,@model 使 PageModel 派生的类IndexModel可用于 Razor 页面。 在页面上通过 @Html.DisplayNameFor 和 @Html.DisplayName HTML 辅助助手使用该实体。

ViewData 和布局

首先,我们看一下下面的布局代码:

@page
@model RazorMvcBooks.Pages.Books.IndexModel

@{
    ViewData["Title"] = "Index";
}

上面的代码就是 Razor 代码转换为 C# 的一个示例。 大括号“{ }” 字符括住 C# 代码块。

PageModel 基类具有 ViewData 字典属性,可用于添加要传递到某个视图的数据。 可以使用键/值模式将对象添加到 ViewData 字典。 在上面的示例中,“Title”属性被添加到 ViewData 字典中。 “Title”属性的在 Pages/_Layout.cshtml 文件中使用。

你可以在Visual Studio 2017中打开 位于 Pages/_Layout.cshtml 文件,我们来看看这个文件中的前几行,便可以发现 “Title”的使用。代码如下。

复制代码
<!DOCTYPE html>
<html> 
<head> 
<meta charset="utf-8" /> 
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
<title>@ViewData["Title"] - RazorMvcBooks</title> 
<environment include="Development"> 
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> 
<link rel="stylesheet" href="~/css/site.css" /> 
</environment> 
@*Markup removed for brevity.*@ 
复制代码

行 @*Markup removed for brevity.*@ 为 Razor 注释。 与 HTML 注释不同 (<!-- -->),Razor 注释不会发送到客户端。

在Visual Studio 2017 中按F5运行应用程序,在浏览器测试项目中的链接(Home、About、Contact、Create、Edit和Delete)。你会发现在浏览器中每个页面的标题都是一样的。当您将某个页面添加到书签时,标题用于这个书签。 Pages/Index.cshtml 和 Pages/Books/Index.cshtml 当前具有相同的标题,但可以修改它们以具有不同的值。

我们可以在Visual Studio 2017中打开 位于  Pages/_ViewStart.cshtml 文件,查看其中的 Layout 属性,如下代码:

@{
    Layout = "_Layout";
}

上面的标记将所有 Razor 页面的布局设置为 Pages 文件夹下的 Pages/_Layout.cshtml所定义的布局。

 修改布局

第一步,我们要使用“书籍管理系统”来替换 Pages/_Layout.cshtml 文件中的 <title> 元素中的RazorMvcBooks字符串。如下代码。

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8" /> 
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
<title>@ViewData["Title"] – 书籍管理系统</title>

第二步,在 Pages/_Layout.cshtml 文件中的找到以下数据信息: 

<a asp-page="/Index" class="navbar-brand">RazorMvcBooks</a>

将上面的数据信息替换为以下数据信息: 

<a asp-page="/Books/Index" class="navbar-brand">书籍管理系统</a>

上面的<a>元素是一个标记辅助助手。此处它是<a>标记辅助助手。asp-page="/Books/Index" 标记辅助助手属性和值可以用来创建指向 /Books/Index  Razor 页面的链接。

保存所做的修改,在Visual Studio 2017中按F5运行程序,在浏览器中通过单击“书籍管理系统”链接测试应用,如下图。