将数据传递给所有页面通用的布局
我有一个网站,有一个布局页面。 然而,这个布局页面有数据,所有页面模型必须提供这样的页面标题,页面名称和我们实际上为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>