我看到的是一个字符串布局属性。但是我如何显式地将模型传递给布局?
我看到的是一个字符串布局属性。但是我如何显式地将模型传递给布局?
示例: 控制器:
public class MyController : Controller
{
public MainLayoutViewModel MainLayoutViewModel { get; set; }
public MyController()
{
this.MainLayoutViewModel = new MainLayoutViewModel();//has property PageTitle
this.MainLayoutViewModel.PageTitle = "my title";
this.ViewData["MainLayoutViewModel"] = this.MainLayoutViewModel;
}
}
布局页面的顶部示例
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
现在你可以在布局页面中引用变量“viewModel”,并完全访问已键入的对象。IActionFilter
,并在OnActionExecuting
中完成完全相同的工作。 在MyController
上放置MyActionFilter
。public class MyActionFilter: Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var myController= context.Controller as MyController;
if (myController!= null)
{
myController.Layout = new MainLayoutViewModel
{
};
myController.ViewBag.MainLayoutViewModel= myController.Layout;
}
}
}
如果你遇到这个问题,那么你的视图模型可能有一些错误。个人而言,我不会为布局页编写代码。但是,如果你想这样做,你应该有一个基础视图模型,其他视图模型都继承自它,并将布局页编写为基础视图模型,将特定页面编写为各自的视图模型。
一种常见的解决方案是创建一个基础视图模型,其中包含布局文件中使用的属性,然后从基础模型继承到各自页面使用的模型。
这种方法的问题在于,现在您已经将自己锁定为模型只能从另一个类继承,而且也许您的解决方案本身就不能在所需的模型上使用继承。
我的解决方案也是从一个基础视图模型开始:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
通过这个解决方案,我已经消除了在布局模型和模型之间需要继承的需求。
现在我可以像这样在Layout.cshtml中使用LayoutModel:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
在页面中,您可以像这样使用通用的LayoutModel:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
在你的控制器中,你只需要返回一个类型为LayoutModel的模型:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
这是非常基础的东西,你只需要创建一个基本视图模型,并确保所有使用该布局的视图都接收使用该基本模型的视图!
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
在_Layout.cshtml文件中:@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
在HomeController中的Index(例如)方法中:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
Index.cshtml页面:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
我不同意将模型传递给_layout是一个错误,一些用户信息可以被传递,并且数据可以在控制器的继承链中填充,因此只需要一个实现。
显然,对于更高级的目的,您应该考虑使用注入创建自定义静态上下文,并将该模型命名空间包含在_Layout.cshtml中。
但对于普通用户来说,这就足够了。
为什么不使用一个具有特定控制器的新部分视图,将所需的模型传递给该部分视图,最后使用 RenderPartial 或 RenderAction 在 Layout.cshtml 上呈现所提到的部分视图?
我使用这种方法来显示已登录用户的信息,例如姓名、个人资料图片等。
虽然这是一个老问题,但是为了回答 MVC5 开发者的疑问,你可以像在视图中一样使用 Model
属性。
在视图和布局中,Model
属性都与相同的 ViewDataDictionary
对象相关联,因此您不需要额外的工作来将模型传递给布局页,并且您不需要在布局中声明 @model MyModelName
。
但请注意,在布局中使用 @Model.XXX
时,智能感知上下文菜单不会出现,因为这里的 Model
是一个动态对象,就像 ViewBag
一样。
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
@inject My.Namespace.IMyLayoutModel myLayoutModel
这是一个有点模糊的领域。但鉴于我在这里看到的极度复杂的替代方案,我认为它是一种为实用性而做出的完全可以接受的例外。特别是如果您确保保持简单,并确保任何繁重的逻辑(我认为真的不应该有,但需求不同)在另一个类/层中,即其所属的位置。这肯定比因为基本上只有一个视图而污染您所有的控制器或模型要好得多。
仅从上述内容来看,但实现简单。
索引页
@model CMS.Models.IndexViewModel
@{
ViewBag.PageModel = Model;
}
布局页面
@{
var Model = (CMS.Models.IndexViewModel)ViewBag.PageModel;
}
还有一种方法可以实现它。
只需为所有控制器实现BaseController类。
在BaseController
类中创建一个返回Model类的方法,例如:
在public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
布局(Layout)
页面中,您可以调用该方法GetTopMenu()
。
@using GJob.Controllers
<header class="header-wrapper border-bottom border-secondary">
<div class="sticky-header" id="appTopMenu">
@{
var menuPageModel = ((BaseController)this.ViewContext.Controller).GetTopMenu();
}
@Html.Partial("_TopMainMenu", menuPageModel)
</div>
</header>
ViewBag.YourObject = yourObject;
2) 在_Layout.cshtml文件的顶部添加一个using语句,其中包含您对象的类定义。例如:
@using YourApplication.YourClasses;
3) 当您在_Layout中引用yourObject时,请进行强制类型转换。您可以进行强制类型转换是因为您在步骤(2)中所做的操作。
Model
已经在_Layout
中可用了。我使用的是 MVC5。 - toddmo