推荐使用 Razor Pages在 [ASP.NET](http://ASP.NET) Core MVC 框架中创建 UI。
首先,在ProductManagement.Web项目的*Pages*文件夹下创建一个*Products文件夹。然后,右键单击Products*文件夹,然后选择**Add**|**Razor Page**。选择**Razor 页面 - 空**选项,命名为`Index.cshtml`。下图显示了我们添加的页面的位置:
![](https://img.kancloud.cn/0b/9c/0b9cdf6d82f11488ef17deed37933671_211x218.png)
编辑内容,`Index.cshtml`如下代码块所示:
```
@page
@using ProductManagement.Web.Pages.Products
@model IndexModel
<h1>Products Page</h1>
```
在这里,我放置一个`h1`元素作为页眉。接下来我们在主菜单中添加一个菜单来打开这个页面。
## 添加菜单项
ABP 提供了一个动态、模块化的菜单系统。每个模块都可以添加到主菜单。
打开*ProductManagement.Web项目的\*\*Menus*文件夹中的`ProductManagementMenuContributor`类,并在`ConfigureMainMenuAsync`方法末尾添加以下代码:
```
context.Menu.AddItem(
new ApplicationMenuItem(
"ProductManagement",
l["Menu:ProductManagement"],
icon: "fas fa-shopping-cart"
).AddItem(
new ApplicationMenuItem(
"ProductManagement.Products",
l["Menu:Products"],
url: "/Products"
)
)
);
```
此代码添加了一个*产品管理*主菜单,其中包含产品菜单项。里面的`l["…"]`语法是用来获取本地化的值。
打开ProductManagement.Domain.Shared 项目的Localization/ProductManagement文件夹中的`en.json`文件,并将以下代码添加到该`texts`部分的末尾:
```
"Menu:ProductManagement": "Product Management",
"Menu:Products": "Products"
```
我们可以使用任意字符串值作为本地化键。在本例中,我们使用`Menu:`作为菜单的本地化键的前缀,例如`Menu:Products` 。我们将在\[*第 8 章*\] *使用 ABP 的功能和服务*中探讨本地化主题。
现在,重新运行,使用新的*产品管理*菜单打开*产品*页面,如图所示:
![](https://img.kancloud.cn/69/41/6941d4392e91905b9edc316f3abe43fd_788x190.png)
## 创建产品数据表
接下来我们将创建一个数据表显示带有分页和排序的产品列表。ABP 启动模板带有预安装和配置的JS 库 [**Datatables.net**](http://Datatables.net),用于显示表格数据。
打开`Index.cshtml`页面(在*Pages/Products*文件夹),并将其内容更改为以下内容:
```
@page
@using ProductManagement.Web.Pages.Products
@using Microsoft.Extensions.Localization
@using ProductManagement.Localization
@model IndexModel
@inject IStringLocalizer<ProductManagementResource> L
@section scripts
{
<abp-script src="/Pages/Products/Index.cshtml.js" />
}
<abp-card>
<abp-card-header>
<h2>@L["Menu:Products"]</h2>
</abp-card-header>
<abp-card-body>
<abp-table id="ProductsTable" striped-rows="true" />
</abp-card-body>
</abp-card>
```
`abp-script`是一个 ABP 标签助手,用于将脚本文件添加到页面,并具有自动捆绑、压缩和版本控制功能。`abp-card`是另一个标签助手,以一种类型安全且简单的方式渲染 Card 组件。
> 我们可以使用标准的 HTML 标签。但是,ABP 标签助手极大地简化了 MVC/Razor 页面中的 UI 创建。此外,它们支持智能感知和编译时错误类型检查。我们将在\[*第 12 章*\] *使用 MVC/Razor 页面*中研究标签助手。
*在Pages/Products*文件夹下创建一个新的 JavaScript 文件,命名为`Index.cshtml.js`,内容如下:
```
$(function () {
var l = abp.localization.getResource('ProductManagement');
var dataTable = $('#ProductsTable').DataTable(
abp.libs.datatables.normalizeConfiguration({
serverSide: true,
paging: true,
order: [[0, "asc"]],
searching: false,
scrollX: true,
ajax: abp.libs.datatables.createAjax(
productManagement.products.product.getList),
columnDefs: [
/* TODO: Column definitions */
]
})
);
});
```
ABP 简化了数据表配置并提供了内置集成:
* `abp.localization.getResource` 返回一个本地化对象,ABP 允许您在 JS中重用服务器端定义的本地化。
* `abp.libs.datatables.normalizeConfiguration`是 ABP 框架定义的辅助函数。它通过为缺失选项提供常规默认值来简化数据表的配置。
* `abp.libs.datatables.createAjax` 使 ABP 的动态 JS 客户端代理来适配数据表的参数格式。
* `productManagement.products.product.getList`是动态JS代理方法。
`columnDefs`数组用于定义数据表中的列:
```
{
title: l('Name'),
data: "name"
},
{
title: l('CategoryName'),
data: "categoryName",
orderable: false
},
{
title: l('Price'),
data: "price"
},
{
title: l('StockState'),
data: "stockState",
render: function (data) {
return l('Enum:StockState:' + data);
}
},
{
title: l('CreationTime'),
data: "creationTime",
dataFormat: 'date'
}
```
通常,列有一个`title`字段和一个`data`字段。`data`字段匹配`ProductDto`类中的属性名称,格式为**驼峰**式(一种命名风格,其中每个单词的第一个字母大写,第一个单词除外;它是JavaScript 语言中常用的命名风格)。
该`render`选项用于精细控制如何显示列数据。
在此页面上,我们使用了一些本地化键。我们应该先在本地化资源中定义它们。打开ProductManagement.Domain.Shared项目的*Localization/ProductManagement* *文件*夹中的`en.json`文件,并在该部分的末尾添加以下条目`texts`:
```
"Name": "Name",
"CategoryName": "Category name",
"Price": "Price",
"StockState": "Stock state",
"Enum:StockState:0": "Pre-order",
"Enum:StockState:1": "In stock",
"Enum:StockState:2": "Not available",
"Enum:StockState:3": "Stopped",
"CreationTime": "Creation time"
```
看一下实际的产品数据表:
![](https://img.kancloud.cn/73/d7/73d79fe9b7564cb97196ac20d2983e92_949x445.png)
至此,我们创建了一个完整的工作页面,列出了支持分页和排序的产品。在接下来的部分中,我们将添加创建、编辑和删除产品的功能。
- 前言
- 第一部分
- 第1章 现代软件开发和 ABP 框架
- 企业级 Web 开发的挑战
- ABP框架的能力清单
- 第2章 ABP框架入门
- 安装 ABP CLI
- 创建新解决方案
- 运行解决方案
- 探索预构建模块
- 第3章 逐步开发开发ABP应用
- 创建解决方案
- 定义领域对象
- EFCore和数据库映射
- 定义应用服务
- 测试产品
- 产品列表
- 创建产品
- 编辑产品
- 删除产品
- 第4章 探索 EventHub解决方案
- 应用介绍
- 架构探索
- 方案运行
- 第二部分
- 第5章 探索ABP基础架构
- 了解模块化
- 使用依赖注入系统
- 配置应用程序
- 实现选项模式
- 日志系统
- 第6章 数据访问基础架构
- 定义实体
- 定义仓储库
- EF Core集成
- 了解 UoW
- 第7章 探索横切关注点
- 认证授权
- 用户验证
- 异常处理
- 第8章 体验 ABP 的功能和服务
- 获取当前用户
- 使用数据过滤
- 控制审计日志
- 缓存数据
- 本地化用户界面
- 第三部分
- 第9章 理解领域驱动设计
- 介绍 DDD
- 构建基于 DDD 的 解决方案
- 处理多个应用程序
- 了解执行流程
- DDD的通用原则
- 第10章 领域层 Domain
- 领域事件案例分析
- 聚合和实体的设计原则和实践
- 实现领域服务
- 落地存储库
- 构建规约(Specification)
- 领域事件
- 第11章 应用层 Application
- 落地应用服务
- 设计 DTO
- 理解各层的职责
- 第四部分
- 第12章 MVC/Razor 页面
- 主题系统
- 绑定和压缩
- 导航菜单
- Bootstrap标签助手
- 创建表单并验证
- 使用模态窗口
- 使用JS API
- 调用HTTP API
- 第13章 Blazor WebAssembly UI
- 什么是Blazor
- ABP Blazor UI
- 验证用户身份
- 理解主题系统
- 使用菜单
- 使用基本服务
- 使用UI服务
- 消费HTTP API
- 使用全局脚本和样式
- 第14章 HTTP API 和实时服务
- 构建HTTP API
- 使用HTTP API
- 使用SignalR
- 第五部分
- 第15章 落地模块化
- 理解模块化
- 构建支付模块
- 安装模块
- 第16章 实现多租户
- 理解多租户
- 多租户基础设施
- 使用功能系统
- 何时使用多租户
- 第17章 构建自动化测试
- 了解ABP测试基础设施
- 构建单元测试
- 构建集成测试