ASP.NET MVC5(三)使用Razor

作者 Zhendong Ho 日期 2021-03-12
ASP.NET MVC5(三)使用Razor

Razor是MVC框架视图引擎的名称。视图引擎负责处理ASP.NET内容,并查找有关指令,将动态内容插入到发送给浏览器的输出。

视图的目标:将模型的一个或多个部分表现给用户。意味着,视图会产生显示数据的HTML,这些数据来自于视图所接收的一个或多个对象。

准备项目

打开VS,创建ASP.NET Web应用程序,项目名称为Razor,选择MVC空模板。

定义模型

在Models文件夹添加Product类。

public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}

定义控制器

添加HomeController。定义Index动作方法,并把Product对象传递给View。

public class HomeController : Controller
{
// 字段
Product myProduct = new Product
{
ProductID = 1,
Name = "Kayak",
Description = "A boat for one person",
Category = "Watersports",
Price = 275M
};

public ActionResult Index()
{
return View(myProduct);
}
}

创建视图

添加Index视图,模板设置为空,选择Product模型类。

使用模型对象

Razor语句@字符开始。@model语句声明了通过动作方法传递给该视图模型对象的类型,我们可以通过@Model来引用视图模型对象的方法字段属性

@model Razor.Models.Product

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
@Model.Name
</div>
</body>
</html>

使用布局

@{ … }Razor代码块,这种代码块允许在视图中包含C#语句。

在MVC应用程序中,Razor视图会被编译成C#类,而所用的基类定义了Layout属性。

Layout属性的值设置为null,代表该视图是自包含的,并且会渲染客户端所需要的全部内容。

创建布局

右键Views文件夹,添加新建项,选择MVC5 布局页,文件名设置为_BasicLayout.cshtml

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<h1>Product Information</h1>
<div style="padding: 20px; border: solid medium black; font-size: 20pt;">
@RenderBody()
</div>
<h2>Visit <a href="http://apress.com">Apress</a></h2>
</body>
</html>

注意

  1. @RenderBody方法的调用会将动作方法所指定的视图内容插入到布局标记之中。
  2. ViewBag.Title会查找Title属性,目的是设置title元素的内容
  3. 代码添加了两个标题元素(h1和h2),以及对div元素运用了一些css样式,目的是让来自布局的内容与来自视图的内容有所区别。

运用布局

为了将布局运用于视图,只需要设置视图的Layout属性的值即可。

布局中包含了一些HTML元素,定义了HTML页面的结构

在Index视图中使用Layout属性。

@model Razor.Models.Product

@{
ViewBag.Title = "Product Name";
Layout = "~/Views/_BasicLayout.cshtml";
}
Product Name: @Model.Name

视图起始文件

如果有多个视图,则必须在每一视图都要指定布局文件,这是难以维护的。

视图起始文件:在渲染一个视图时,MVC框架会查找一个叫做_ViewStart.cshtml的文件。框架会将此文件的内容视为视图文件的一部分

在Views文件夹添加MVC5 布局页,名称设置为_ViewStart.cshtml

@{
Layout = "~/Views/_BasicLayout.cshtml";
}

这样就可以在Index视图中去掉Layout属性。

@model Razor.Models.Product

@{
ViewBag.Title = "Product Name";
}
Product Name: @Model.Name

注意

  1. 如果添加了视图起始文件_ViewStart.cshtml,则MVC会对此文件进行定位且自动使用其内容(所有视图默认使用视图起始文件的布局)
  2. 如果在视图中重新定义了Layout的值,则会覆盖视图起始文件中所指定的布局。(Layout优先级:视图 > 视图起始文件)
  3. Layout属性设置为null,与不使用Layout属性是不同的。

共享布局

HomeController中添加NameAndPrice动作方法。

public ActionResult NameAndPrice()
{
return View(myProduct);
}

添加NameAndPrice视图,选择Product模型类,勾选使用布局页,选择_BasicLayout.cshtml。(这里如果不勾选布局页,也是同样的结果,因为视图起始文件引用了相同的布局)

@model Razor.Models.Product

@{
ViewBag.Title = "NameAndPrice";
Layout = "~/Views/_BasicLayout.cshtml";
}

<h2>NameAndPrice</h2>
The product name is @Model.Name and it costs $@Model.Price

Razor表达式

动作方法与视图所起的作用。

组件 要做的事 不做的事
动作方法 向视图传递一个视图模型 向视图传递格式化的数据
视图 用视图模型对象向用户表现内容 修改视图模型对象的任何方面

当然可以在动作方法中创建要显示的字符串,并把它作为视图模型传递给视图,但这破坏了MVC模式的好处。

插入数据值

Razor表达式能做的最简单的事情,是将数据值插入到标记中,可以用@Model表达式来做这件事,以引用视图模型对象所定义的属性与方法。或使用@ViewBag表达式引用动态属性。

在HomeController添加DemoExpressions动作方法。

public ActionResult DemoExpressions()
{
ViewBag.ProductCount = 1;
ViewBag.ExpressShip = true;
ViewBag.ApplyDiscount = false;
ViewBag.Supplier = null;

return View(myProduct);
}

创建DemoExpressions视图,选择Product模型类。视图使用Razor表达式显示数据,这些数据是动作方法传递给视图的。

@model Razor.Models.Product

@{
ViewBag.Title = "DemoExpression";
}

<table>
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>Price</td>
<td>@Model.Price</td>
</tr>
<tr>
<td>Stock Level</td>
<td>@ViewBag.ProductCount</td>
</tr>
</tbody>
</table>

设置标签属性的值

可以通过Razor表达式,设置元素的标签属性的值。

修改DemoExpression视图,在视图中使用Razor表达式设置标签属性值

@model Razor.Models.Product

@{
ViewBag.Title = "DemoExpression";
}

<table>
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>Price</td>
<td>@Model.Price</td>
</tr>
<tr>
<td>Stock Level</td>
<td>@ViewBag.ProductCount</td>
</tr>
</tbody>
</table>

<div data-discount="@ViewBag.ApplyDiscount" data-express="@ViewBag.ExpressShip" data-supplier="@ViewBag.Supplier">
The containing element has data attributes
</div>

Discount:<input type="checkbox" checked="@ViewBag.ApplyDiscount" />
Express:<input type="checkbox" checked="@ViewBag.ExpressShip" />
Supplier:<input type="checkbox" checked="@ViewBag.Supplier" />

注意

  1. data标签属性,以data-为前缀,作为创建自定义标签属性的一种非正规方式,现已称为H5的正规标准
  2. Razor会将后台的null渲染成空字符串。如Supplier标签属性。
  3. Razor使用checked标签属性时,用是否出现该标签属性而不是它的值来改变元素的配置。即,Razor在值为Falsenull时,会完全删除该标签属性。如ApplyDiscount和Supplier标签属性。

使用条件语句

Razor能处理条件语句,这是Razor的核心功能。这能够创建复杂而流畅的视图,使视图仍易于阅读和维护。

修改DemoExpression视图,在视图中使用Razor条件语句

@model Razor.Models.Product

@{
ViewBag.Title = "DemoExpression";
}

<table>
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>Price</td>
<td>@Model.Price</td>
</tr>
<tr>
<td>Stock Level</td>
<td>
@switch ((int)ViewBag.ProductCount)
{
case 0:
@: Out of Stock
break;
case 1:
<b>Low Stock (@ViewBag.ProductCount)</b>
break;
default:
@ViewBag.ProductCount
break;
}
</td>
</tr>
</tbody>
</table>

注意

  1. 在视图中使用switch表达式,需要使用@switch开头。
  2. 必须将ViewBag.ProductCount属性的值转换成int才能够在switch语句中使用。因为Razor中的switch表达式不能求取动态属性的值
  3. 如果使用@:前缀,则Razor阻止此行解释为一条C#语句。可以用此方法,将HTML元素中的文本插入到视图

修改DemoExpression视图,在视图中使用if语句(与switch语句结果相同)。

@model Razor.Models.Product

@{
ViewBag.Title = "DemoExpression";
}

<table>
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>@Model.Name</td>
</tr>
<tr>
<td>Price</td>
<td>@Model.Price</td>
</tr>
<tr>
<td>Stock Level</td>
<td>
@if (ViewBag.ProductCount == 0)
{
@: Out of Stock
}
else if (ViewBag.ProductCount == 1)
{
<b>Low Stock (@ViewBag.ProductCount)</b>
}
else
{
@ViewBag.ProductCount
}
</td>
</tr>
</tbody>
</table>

枚举数组和集合

在HomeController添加DemoArray动作方法。该动作方法创建了Product[]对象,并传递给View方法。

public ActionResult DemoArray()
{
Product[] array = {
new Product { Name = "Kayak", Price = 275M },
new Product { Name = "Lifejacket", Price = 48.95M },
new Product { Name = "Soccer ball", Price = 19.50M },
new Product { Name = "Corner flag", Price = 34.95M }
};

return View(array);
}

VS的支架特性不能指定一个数组作为模型类,但Razor本身能够支持数组。

创建一个不含模型DemoArray视图,手动添加@model表达式

@model Razor.Models.Product[]

@{
ViewBag.Title = "DemoArray";
}

@if (Model.Length > 0)
{
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (Razor.Models.Product p in Model)
{
<tr>
<td>@p.Name</td>
<td>@p.Price</td>
</tr>
}
</tbody>
</table>
}
else
{
<h2>No product data</h2>
}

处理命名空间

可以对一个视图运用@using表达式,以引入命名空间,就像在C#类那样。一个视图可以包含多个@using表达式。

在DemoArray视图中运用@using表达式,并去掉@model表达式和foreach循环中的命名空间

@using Razor.Models
@model Product[]

@{
ViewBag.Title = "DemoArray";
}

@if (Model.Length > 0)
{
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (Product p in Model)
{
<tr>
<td>@p.Name</td>
<td>@p.Price</td>
</tr>
}
</tbody>
</table>
}
else
{
<h2>No product data</h2>
}