.NET Core第13天_View常见操作_Layout布局页_PartialView部分检视_强类型视图(大量资料或物件的传递)

_Layout布局(版面配置)页

预设当我们新建好.net5 mvc专案後
比方今天新增一个空的Razor检视
当执行在浏览器呈现时候会发现被套用到一个预设布局页

https://ithelp.ithome.com.tw/upload/images/20210914/20107452Gvpm7vwC48.png

主要原因在於
.net core mvc预设会产生和之前.net webform MasterPage
有点类似的布局套版页机制
_ViewStart.cshtml

本质也是一个View但主要是跟MasterPage一样的定义布局页(布局视图)
_ViewStart.cshtml会比其他所有视图都还要优先被运行

Layout这里有指定一个名称_Layout代表指向_Layout.cshtml,
而_Layout.cshtml才是真正的布局内容。

专案目录摆放层级
./Views/_ViewStart.cshtml
./Views/Shared/_Layout.cshtml

https://ithelp.ithome.com.tw/upload/images/20210914/20107452nzsrq5z93L.png

_Layout.cshtml布局实质前端档案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Net5MvcApp1</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Net5MvcApp1</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            © 2021 - Net5MvcApp1 - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

当中主要负责变化引入Content页采用@RenderBody()语法
来做套版

假设我们Add.cshtml不想套用布局页
则可以在档案中用Razor语法来指定Layout为null即可

https://ithelp.ithome.com.tw/upload/images/20210914/20107452Rmrvub10Tf.png

那想自行创建一个布局页
也是可以就在Shared目录下
新建Razor版面配置页(布局),命名通常习惯以下滑线为开头。

https://ithelp.ithome.com.tw/upload/images/20210914/20107452ONYVNfRuT1.png

预设就会帮我们安插好@RenderBody()
https://ithelp.ithome.com.tw/upload/images/20210914/20107452Cl3YLC3uRw.png

假设这里设置一个简单样式
_Site.cshtml

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <div style="color:red;">
        @RenderBody()
    </div>
</body>
</html>

在去_ViewStart.cshtml来做全域性更改设置

https://ithelp.ithome.com.tw/upload/images/20210914/201074525up07p35NB.png

再去运行即可套用自己设置的版面配置
https://ithelp.ithome.com.tw/upload/images/20210914/20107452WJsPNkwcn4.png

版面配置页在设置上可以单指定档名,也可指定完整路径。
这里创建额外的版面配置页

./Views/Shared/_SiteLayout.cshtml

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <div style="height:50px; width:100%; background-color:blue;color:white;">
        <span>SiteLayout测试版面配置</span>
    </div>
    <div style="height:500px;">
        @RenderBody()
    </div>
    <div style="height: 30px; width: 100%; background-color: red; color: white;">
        底部
    </div>
</body>
</html>

新增额外一个ProductController.cs,两个action method (Index , Show)

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5MvcApp1.Controllers
{
    public class ProductController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Show()
        {
            return View();
        }
    }
}

各自都采用默认检视
.\Views\Product\Index.cshtml
单指定档名

@{ 
    Layout = "_SiteLayout";
}

<div>
    Product-视图页Index
</div>

.\Views\Product\Show.cshtml
指定完整路径

@{
    Layout = "/Views/Shared/_SiteLayout.cshtml";
}

<div>
    Product-视图页Show
</div>

运行效果
https://ithelp.ithome.com.tw/upload/images/20210914/20107452Qzui8fqjqo.png

上面是一个View就指定一次的方式
若今天视图有100个就要重复100次
若不想这麽累可以直接从_ViewStart.cshtml
更改默认全域版面配置(布局)页,之後每页就不需要去设置Layout了。

分布视图、部分检视/PartialView

主要用於某个主视图中的部分内容,常用在部分内容更新。
於Controller当中会使用 PartialView()语法来回传
可返回指定的View或Model Entity,跟View()使用一样。
跟一般的不需要引用布局页。

分布视图的新建
在./Views/Product 目录新建检视(跟一般检视新增方式一样)

https://ithelp.ithome.com.tw/upload/images/20210914/201074525y8xvRCRCg.png

https://ithelp.ithome.com.tw/upload/images/20210914/20107452Adf3SmP7AO.png

return partial view语法

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5MvcApp1.Controllers
{
    public class ProductController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Show()
        {
            return View();
        }

        public IActionResult Add()
        {
            return PartialView("_Partial01");
        }
    }
}

https://ithelp.ithome.com.tw/upload/images/20210914/201074523wpFxyPOfG.png

运行效果
没有被套用全域默认版面配置
https://ithelp.ithome.com.tw/upload/images/20210914/20107452aJ7E3sO3N5.png

若在某一个主页面比方Product的Show检视
去加载分布视图
此时可以在检视中使用partial tag来实践

@{
    Layout = "/Views/Shared/_SiteLayout.cshtml";
}

<div>
    Product-视图页Show
</div>

<div>
    <partial name="/Views/Product/_Partial01.cshtml" />
</div>

https://ithelp.ithome.com.tw/upload/images/20210914/20107452vxyGzoT0kw.png

PartialView的tag写法主要是取代
Html.Partial 、 Html.RenderPartial这两个同步的写法方式
但有时你的分布页可能会需要等待loading这时
会建议改采用非同步处理
也就是不会有上半部没Load完下半部也会Delay
写法也可以换成@await Html.PartialAsync("分布视图路径")
或者@{await Html.RenderPartialAsync("/Views/Product/_Partial01.cshtml");}
以下是程序范本

@{
    Layout = "/Views/Shared/_SiteLayout.cshtml";
}
<div>
    Product-视图页Show
</div>
<div>
    @*第1种.partial tag Tag helper*@
    <partial name="/Views/Product/_Partial01.cshtml" />

    @* 同步的方式-------*@
    
    @*Html Helper第1种.Html.Partial*@
    @Html.Partial("/Views/Product/_Partial01.cshtml")
    @*Html Helper第2种.Html.RenderPartial*@
    @{
        Html.RenderPartial("/Views/Product/_Partial01.cshtml");
    }

    @* 同步的方式-------*@

    @* 非同步的方式-------*@
    
    @*Html Helper第1种.Html.PartialAsync*@
    @await Html.PartialAsync("/Views/Product/_Partial01.cshtml")

    @*Html Helper第2种.Html.RenderPartialAsync*@
    @{
        await Html.RenderPartialAsync("/Views/Product/_Partial01.cshtml");
    }

    @* 非同步的方式-------*@

</div>

<div>
    後面的网页内容
</div>

View资料传递

从Controller要传递资料到View基本上跟以前的.net mvc也没有舍麽不同
ASP.NET MVC(六)_ViewData,ViewBag,TempData用法与差异比较

https://ithelp.ithome.com.tw/upload/images/20210914/20107452HYbvI4yUgy.png

在View内传递值也是可以的
https://ithelp.ithome.com.tw/upload/images/20210914/20107452lnKQTkvmUp.png

版面配置页跟View之间传递资料方式
比方预设的_Layout中有一个Title的ViewData
在版面配置页有默认值

https://ithelp.ithome.com.tw/upload/images/20210914/20107452gLLSGOfZCs.png

但是当到了特定单一View
比方Home的Index或是Privacy
就又被客制指定为别的标题文字内容
https://ithelp.ithome.com.tw/upload/images/20210914/20107452Xes7SmpICm.png

强类型(型别)视图(大量资料或物件的传递)
在从控制器要传送资料到View过程若只是单纯的string或者数值要传送可以依赖
ViewData , ViewBag

但若需要向VIew传送比较大量的资料或者要有跨server互动作用的资料
则会建议采用强类型(型别)视图机制

一般Model 物件传递方式

在Models目录新增一个Class (模型类别)
命名为BookViewModel
(BookViewModel.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5MvcApp1.Models
{
    public class BookViewModel
    {
        public string Name { get; set; }
        public double Price { get; set; }
    }
}

建立好Book控制器并撰写程序
BookController.cs

using Microsoft.AspNetCore.Mvc;
using Net5MvcApp1.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5MvcApp1.Controllers
{
    public class BookController : Controller
    {
        public IActionResult Index()
        {
            List<BookViewModel> bookViewModels = new List<BookViewModel>()
            {
                new BookViewModel(){Name="外宿族必备宝典:1次搞懂租屋细节",Price=300},
                new BookViewModel(){Name="年年18%,一生理财这样做就对了(全新修订版)",Price=380},
                new BookViewModel(){Name="无脑理财术,小资大翻身!:无论起薪多少都受用的超简单投资法",Price=320}
            };
            ViewBag.BookList = bookViewModels;
            return View();
        }
    }
}

与新增预设View後
./Views/Book/Index.cshtml

<table class="table table-bordered">
    <tr class="bg-primary">
        <td style="color:white">图书名称</td>
        <td style="color:white">图书单价</td>
    </tr>
    @foreach (var item in ViewBag.BookList)
    {
        <tr>
            <td>@item.Name</td>
            <td>@item.Price</td>
        </tr>
    }

</table>

运行结果即可看到
https://ithelp.ithome.com.tw/upload/images/20210914/20107452M5LLa7v3XF.png

透过ViewBag将dynamic书单列表呈现在View中
但当栏位一多的时候这种方式可能比较不方便没有智能提示容易打错

因此也可以透过IEnumerable的泛型来做传递,在遍历Book Model的时候
就能有智能提示对应属性

<table class="table table-bordered">
    <tr class="bg-primary">
        <td style="color:white">图书名称</td>
        <td style="color:white">图书单价</td>
    </tr>
    @foreach (var item in ViewBag.BookList as IEnumerable<Net5MvcApp1.Models.BookViewModel>)
    {
        <tr>
            <td>@item.Name</td>
            <td>@item.Price</td>
        </tr>
    }

</table>

https://ithelp.ithome.com.tw/upload/images/20210914/20107452Dmn4VG9tS5.png

但可能仍有一些美中不足
我们不想每次在IEnumerable里面都要把整个命名空间写进来有点太长
在View里面当然也可省略命名空间
https://ithelp.ithome.com.tw/upload/images/20210914/20107452N9N9y4xSpi.png

可以省略主因在於.net core MVC中有提供一个导入文件
./Views/_ViewImports.cshtml
里面自动引入该name space

https://ithelp.ithome.com.tw/upload/images/20210914/20107452H1sHOKDia4.png

强类型(型别)视图传递方式

不透过ViewData或ViewBag这些不确定的型别(泛型列表)
而是采用具体的Class型态(强型别)在控制器和视图之间做资料传递互动,将Model跟View结合起来组成的View就称为强类型(型别)视图。

於Controller直接透过 return View(某型别物件(集合) )回传,也就是给ViewData中的Model赋值。
於View当中可以用List<某型别物件> 或IEnumerable<某型别物件>方式遍历

https://ithelp.ithome.com.tw/upload/images/20210914/20107452Ie1PnVvFIx.png

强型别传入模型的BookController.cs

using Microsoft.AspNetCore.Mvc;
using Net5MvcApp1.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Net5MvcApp1.Controllers
{
    public class BookController : Controller
    {
        public IActionResult Index()
        {
            List<BookViewModel> bookViewModels = new List<BookViewModel>()
            {
                new BookViewModel(){Name="外宿族必备宝典:1次搞懂租屋细节",Price=300},
                new BookViewModel(){Name="年年18%,一生理财这样做就对了(全新修订版)",Price=380},
                new BookViewModel(){Name="无脑理财术,小资大翻身!:无论起薪多少都受用的超简单投资法",Price=320}
            };
            //ViewBag.BookList = bookViewModels;
            return View(bookViewModels);
        }
    }
}

强型别视图访问的View(./Views/Book/Index.cshtml)

<table class="table table-bordered">
    <tr class="bg-primary">
        <td style="color:white">图书名称</td>
        <td style="color:white">图书单价</td>
    </tr>

    @model List<BookViewModel>
    @foreach (var item in Model)
    {
        <tr>
            <td>@item.Name</td>
            <td>@item.Price</td>
        </tr>
    }
</table>

在.net core mvc当中的razor语法则跟之前.net mvc是一样的
ASP.NET MVC(五)_Razor语法笔记
就不再多赘述

本篇同步发表至个人部落格
https://coolmandiary.blogspot.com/2021/07/net-core13viewlayout.html

Ref:
The Partial Tag Helper
https://www.learnrazorpages.com/razor-pages/tag-helpers/partial-tag-helper

5 ways to render a partial view in asp.net core
https://nitishkaushik.com/how-to-render-a-partial-view-in-asp-net-core/


<<:  Day1 - Powershell 入门之开始

>>:  【Day3】[资料结构]-链结串列Linked List

Backtrader - 指标使用

以下内容皆参考 Backtrader 官网 在评估股票的时候,我们常常会用一些指标来辅助,今天来介绍...

Day 17:上架 Google Play

前言 当我们终於准备上架 Google Play,我们需要决定在哪些国家、年龄层、装置等才能够看到我...

Day09 - 语音特徵正规化

当一个模型的训练资料和测试资料,彼此之间的资料分布有不匹配(mismatch)时,模 型的性能会出现...

[DAY-12] 除去大部分控制 充分资讯 放心授权

加以控管 vs. 给予资讯 控管式 老板核准及指挥所有提案 行动和团队决策 有时候会直接监督 来控制...

Day 1 - 前言与主题由来

既然是第一天,不免俗的还是要来自我介绍跟前言一下XD 欢迎来到 30 天我与 Vue 的那些二三事。...