将数据传递给所有页面通用的布局
我有一个网站,有一个布局页面。 然而,这个布局页面有数据,所有页面模型必须提供这样的页面标题,页面名称和我们实际上为HTML帮手执行某些操作的位置。 另外每个页面都有自己的视图模型属性。
我该怎么做? 这似乎是一个不好的主意,键入一个布局,但我怎么传递这些信息?
如果您需要将相同的属性传递给每个页面,那么创build所有视图模型使用的基本视图模型将是明智的。 你的布局页面可以采用这个基础模型。
如果在这个数据后面有逻辑要求,那么这个应该被放入一个由所有控制器使用的基础控制器。
有很多事情你可以做,重要的方法是不要在多个地方重复相同的代码。
编辑:从下面的评论更新
这是一个简单的例子来展示这个概念。
创build一个所有视图模型都将从中inheritance的基础视图模型。
public abstract class ViewModelBase { public string Name { get; set; } } public class HomeViewModel : ViewModelBase { }
你的布局页面可以把它作为模型。
@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>
最后在action方法中设置数据。
public class HomeController { public ActionResult Index() { return this.View(new HomeViewModel { Name = "Bacon" }); } }
我在布局中使用了RenderAction html helper作为剃刀。
@{ Html.RenderAction("Action", "Controller"); }
我需要它为简单的string。 所以我的行动返回string,并写下来容易在视图中。 但是,如果您需要复杂的数据,您可以返回PartialViewResult和模型。
public PartialViewResult Action() { var model = someList; return PartialView("~/Views/Shared/_maPartialView.cshtml", model); }
你只需要把你创build的局部视图'_maPartialView.cshtml'的模型开始
@model List<WhatEverYourObjeIs>
然后,您可以使用HTML在该部分视图模型中使用数据。
另一种select是创build一个单独的LayoutModel类,其中包含布局中需要的所有属性,然后将此类的一个实例填充到ViewBag中。 我使用Controller.OnActionExecuting方法来填充它。 然后,在布局的开始,您可以从ViewBag中取回这个对象,并继续访问这个强types的对象。
据推测,主要用例是为所有(或大部分)控制器操作获取基本模型。
鉴于此,我已经使用了几个这些答案的组合,主要支持科林培根的答案。
这是正确的,这仍然是控制器逻辑,因为我们填充视图模型返回到视图。 因此把这个放在控制器里的正确位置。
我们希望在所有的控制器上都发生这种情况,因为我们使用这个布局页面。 我正在使用它在布局页面中呈现的部分视图。
我们还想要一个强types的ViewModel的附加好处
因此,我创build了一个BaseViewModel和BaseController。 所有ViewModel控制器将分别从BaseViewModel和BaseControllerinheritance。
代码:
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!"; } }
注意从这个SOpost中使用OnActionExecuted
HomeController的
public class HomeController : BaseController { public ActionResult Index(string id) { HomeIndexModel model = new HomeIndexModel(); // populate HomeIndexModel ... return View(model); } }
BaseViewModel
public class BaseViewModel { public string AwesomeModelProperty { get; set; } public FooterModel FooterModel { get; set; } }
HomeViewModel
public class HomeIndexModel : BaseViewModel { public string FirstName { get; set; } // other awesome properties }
FooterModel
public class FooterModel { public string FooterModelProperty { get; set; } }
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>
_Nav.cshtml
@model string <nav> <ul> <li> <a href="@Model" target="_blank">Mind Blown!</a> </li> </ul> </nav>
希望这有助于。
如果你想在布局中传递一个完整的模型:
@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>
并将其添加到控制器中:
public ActionResult _Header(ViewAsModelBase model)
您不必混淆操作或更改模型,只需使用基本控制器并从layout viewcontext转换现有的控制器即可。
用所需的公共数据(标题/页面/位置等)和动作初始化创build一个基础控制器…
public abstract class _BaseController:Controller { public Int32 MyCommonValue { get; private set; } protected override void OnActionExecuting(ActionExecutingContext filterContext) { MyCommonValue = 12345; base.OnActionExecuting(filterContext); } }
确保每个控制器都使用基本控制器…
public class UserController:_BaseController {...
从_Layout.cshml
页面的视图上下文中_Layout.cshml
现有的基础控制器…
@{ var myController = (_BaseController)ViewContext.Controller; }
现在,您可以从布局页面中引用基本控制器中的值。
@myController.MyCommonValue
其他答案几乎涵盖了我们如何将模型传递给布局页面的一切。 但是我find了一种方法,使用它可以dynamic地将variables传递到布局页面,而无需在布局中使用任何模型或局部视图。 让我们说你有这个模型 –
public class SubLocationsViewModel { public string city { get; set; } public string state { get; set; } }
你想要dynamic获取城市和州。 例如
在你的index.cshtml中,你可以把这两个variables放在ViewBag中
@model MyProject.Models.ViewModel.SubLocationsViewModel @{ ViewBag.City = Model.city; ViewBag.State = Model.state; }
然后在你的layout.cshtml中,你可以访问这些viewbagvariables
<div class="text-wrap"> <div class="heading">@ViewBag.City @ViewBag.State</div> </div>
我不认为这些答案对于大型企业级应用程序来说足够灵活。 我不是过度使用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); } }
然后在你的_Layout.cshtml从ViewBag拉ViewModel …
@{ LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel; } <h1>@model.Title</h1>
要么…
<h1>@ViewBag.LayoutViewModel.Title</h1>
这样做不会影响页面控制器或视图模型的编码。
创build一个代表布局视图模型的基本视图是一个可怕的方法。 想象一下,你想有一个模型,代表在布局中定义的导航。 你会做CustomersViewModel : LayoutNavigationViewModel
? 为什么? 为什么要通过解决scheme中的每个视图模型传递导航模型数据?
布局视图模型应该是专用的,并且不应该强制视图模型的其余部分依赖于它。
相反,您可以在_Layout.cshtml
文件中执行此操作:
@{ var model = DependencyResolver.Current.GetService<MyNamespace.LayoutViewModel>(); }
最重要的是,我们不需要new LayoutViewModel()
,我们将得到所有的LayoutViewModel
已经解决的依赖关系。
例如
public class LayoutViewModel { private readonly DataContext dataContext; private readonly ApplicationUserManager userManager; public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager) { } }
而不是通过这个,你总是可以使用另一种方法,也是快速的
在共享目录中创build一个新的局部视图,并在您的布局中调用您的局部视图
@Html.Partial("MyPartialView")
在你的局部视图中,你可以调用你的数据库并执行你想做的事情
@{ IEnumerable<HOXAT.Models.CourseCategory> categories = new HOXAT.Models.HOXATEntities().CourseCategories; } <div> //do what ever here </div>
假设你已经添加了你的entity framework数据库
你可以这样使用:
@{ ApplicationDbContext db = new ApplicationDbContext(); IEnumerable<YourModel> bd_recent = db.YourModel.Where(m => m.Pin == true).OrderByDescending(m=>m.ID).Select(m => m); } <div class="col-md-12"> <div class="panel panel-default"> <div class="panel-body"> <div class="baner1"> <h3 class="bb-hred">Recent Posts</h3> @foreach(var item in bd_recent) { <a href="/BaiDangs/BaiDangChiTiet/@item.ID">@item.Name</a> } </div> </div> </div> </div>