我有一个有布局页面的网站.但是,此布局页面包含所有页面模型必须提供的数据,例如页面标题,页面名称以及我们实际执行某些操作的HTML帮助程序所在的位置.每个页面都有自己的视图模型属性.
我怎样才能做到这一点?键入布局似乎是一个坏主意但我如何通过这些信息呢?
Col*_*con 136
如果您需要将相同的属性传递给每个页面,那么创建所有视图模型使用的基本视图模型将是明智的.然后,您的布局页面可以采用此基本模型.
如果此数据背后需要逻辑,则应将其放入所有控制器使用的基本控制器中.
你可以做很多事情,重要的方法是不要在多个地方重复相同的代码.
编辑:从下面的评论更新
这是一个演示概念的简单示例.
创建所有视图模型将继承的基本视图模型.
public abstract class ViewModelBase
{
public string Name { get; set; }
}
public class HomeViewModel : ViewModelBase
{
}
Run Code Online (Sandbox Code Playgroud)
您的布局页面可以将其作为模型.
@model ViewModelBase
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Test</title>
</head>
<body>
<header>
Hello @Model.Name
</header>
<div>
@this.RenderBody()
</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
最后在action方法中设置数据.
public class HomeController
{
public ActionResult Index()
{
return this.View(new HomeViewModel { Name = "Bacon" });
}
}
Run Code Online (Sandbox Code Playgroud)
Bur*_*urk 64
我在布局中使用了RenderAction html helper for razor.
@{
Html.RenderAction("Action", "Controller");
}
Run Code Online (Sandbox Code Playgroud)
我需要它用于简单的字符串.所以我的动作返回字符串并在视图中轻松写下来.但是如果您需要复杂的数据,可以返回PartialViewResult和model.
public PartialViewResult Action()
{
var model = someList;
return PartialView("~/Views/Shared/_maPartialView.cshtml", model);
}
Run Code Online (Sandbox Code Playgroud)
您只需要将您创建的部分视图"_maPartialView.cshtml"的模型开头
@model List<WhatEverYourObjeIs>
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用html在该局部视图中使用模型中的数据.
Den*_*kem 35
另一种选择是创建一个单独的LayoutModel类,其中包含布局中需要的所有属性,然后将此类的实例填充到ViewBag中.我使用Controller.OnActionExecuting方法来填充它.然后,在布局开始时,您可以从ViewBag中拉回此对象并继续访问此强类型对象.
dri*_*zie 26
据推测,这个的主要用例是为所有(或大多数)控制器操作获取基本模型.
考虑到这一点,我使用了其中几个答案的组合,主要是对科林培根的回答.
这仍然是控制器逻辑是正确的,因为我们正在填充视图模型以返回到视图.因此,放置它的正确位置在控制器中.
我们希望在所有控制器上都能实现这一点,因为我们将它用于布局页面.我正在将它用于在布局页面中呈现的部分视图.
我们还希望获得强类型ViewModel的额外好处
因此,我创建了一个BaseViewModel和BaseController.所有ViewModels控制器将分别从BaseViewModel和BaseController继承.
代码:
BaseController
public class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var model = filterContext.Controller.ViewData.Model as BaseViewModel;
model.AwesomeModelProperty = "Awesome Property Value";
model.FooterModel = this.getFooterModel();
}
protected FooterModel getFooterModel()
{
FooterModel model = new FooterModel();
model.FooterModelProperty = "OMG Becky!!! Another Awesome Property!";
}
}
Run Code Online (Sandbox Code Playgroud)
请注意从此SO帖子中使用的OnActionExecuted
HomeController的
public class HomeController : BaseController
{
public ActionResult Index(string id)
{
HomeIndexModel model = new HomeIndexModel();
// populate HomeIndexModel ...
return View(model);
}
}
Run Code Online (Sandbox Code Playgroud)
BaseViewModel
public class BaseViewModel
{
public string AwesomeModelProperty { get; set; }
public FooterModel FooterModel { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
HomeViewModel
public class HomeIndexModel : BaseViewModel
{
public string FirstName { get; set; }
// other awesome properties
}
Run Code Online (Sandbox Code Playgroud)
FooterModel
public class FooterModel
{
public string FooterModelProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Layout.cshtml
@model WebSite.Models.BaseViewModel
<!DOCTYPE html>
<html>
<head>
< ... meta tags and styles and whatnot ... >
</head>
<body>
<header>
@{ Html.RenderPartial("_Nav", Model.FooterModel.FooterModelProperty);}
</header>
<main>
<div class="container">
@RenderBody()
</div>
@{ Html.RenderPartial("_AnotherPartial", Model); }
@{ Html.RenderPartial("_Contact"); }
</main>
<footer>
@{ Html.RenderPartial("_Footer", Model.FooterModel); }
</footer>
< ... render scripts ... >
@RenderSection("scripts", required: false)
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
_Nav.cshtml
@model string
<nav>
<ul>
<li>
<a href="@Model" target="_blank">Mind Blown!</a>
</li>
</ul>
</nav>
Run Code Online (Sandbox Code Playgroud)
希望这会有所帮助.
您不必乱用操作或更改模型,只需使用基本控制器并从布局viewcontext中转换现有控制器.
使用所需的公共数据(标题/页面/位置等)和操作初始化创建基本控制器...
public abstract class _BaseController:Controller {
public Int32 MyCommonValue { get; private set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
MyCommonValue = 12345;
base.OnActionExecuting(filterContext);
}
}
Run Code Online (Sandbox Code Playgroud)
确保每个控制器都使用基本控制器......
public class UserController:_BaseController {...
Run Code Online (Sandbox Code Playgroud)
从_Layout.cshml页面中的视图上下文中转换现有的基本控制器...
@{
var myController = (_BaseController)ViewContext.Controller;
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以从布局页面引用基本控制器中的值.
@myController.MyCommonValue
Run Code Online (Sandbox Code Playgroud)
还有另一种方法来处理这个。从架构的角度来看,这可能不是最干净的方法,但它避免了与其他答案有关的很多痛苦。只需在 Razor 布局中注入一个服务,然后调用一个获取必要数据的方法:
@inject IService myService
Run Code Online (Sandbox Code Playgroud)
然后在布局视图中:
@if (await myService.GetBoolValue()) {
// Good to go...
}
Run Code Online (Sandbox Code Playgroud)
同样,在架构方面不干净(显然服务不应该直接注入到视图中),但它完成了工作。
如果你想传递整个模型,请在布局中像这样:
@model ViewAsModelBase
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8"/>
<link href="/img/phytech_icon.ico" rel="shortcut icon" type="image/x-icon" />
<title>@ViewBag.Title</title>
@RenderSection("styles", required: false)
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
@RenderSection("scripts", required: false)
@RenderSection("head", required: false)
</head>
<body>
@Html.Action("_Header","Controller", new {model = Model})
<section id="content">
@RenderBody()
</section>
@RenderSection("footer", required: false)
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
并将其添加到控制器中:
public ActionResult _Header(ViewAsModelBase model)
Run Code Online (Sandbox Code Playgroud)
小智 5
我认为这些答案对于大型企业级应用程序来说都不够灵活。我不喜欢过度使用 ViewBag,但在这种情况下,为了灵活性,我会破例。这就是我要做的...
您的所有控制器上都应该有一个基本控制器。在基本控制器中添加布局数据 OnActionExecuting (如果您想推迟,则添加 OnActionExecuted )...
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext
filterContext)
{
ViewBag.LayoutViewModel = MyLayoutViewModel;
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
return View(homeModel);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的 _Layout.cshtml 中从 ViewBag 中提取你的 ViewModel ...
@{
LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel;
}
<h1>@model.Title</h1>
Run Code Online (Sandbox Code Playgroud)
或者...
<h1>@ViewBag.LayoutViewModel.Title</h1>
Run Code Online (Sandbox Code Playgroud)
这样做不会干扰页面控制器或视图模型的编码。
| 归档时间: |
|
| 查看次数: |
133481 次 |
| 最近记录: |