Я вижу свойство строкового макета. Но как я могу явно передать модель в макет?
Model
доступен в формате _Layout
. Я использую MVC5.
Я вижу свойство строкового макета. Но как я могу явно передать модель в макет?
Model
доступен в формате _Layout
. Я использую MVC5.
Ответы:
Похоже, вы смоделировали свои модели просмотра немного неправильно, если у вас есть эта проблема.
Лично я бы никогда не стал печатать макет страницы. Но если вы хотите сделать это, у вас должна быть базовая модель просмотра, от которой наследуются другие ваши модели просмотра, и ввести свой макет в базовую модель просмотра, а страницы - на конкретную.
Пример: Контроллер:
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 на странице макета с полным доступом к типизированному объекту.
Мне нравится этот подход, потому что это контроллер, который управляет макетом, в то время как отдельные модели просмотра страниц остаются агностическими.
Примечания для MVC Core
IActionFilter
и выполнение той же самой работы в OnActionExecuting
. Наденьте MyActionFilter
свой MyController
.
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 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...
в методе 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.
но для обычных пользователей это поможет
Распространенное решение - создать базовую модель представления, которая содержит свойства, используемые в файле макета, а затем унаследовать от базовой модели модели, используемые на соответствующих страницах.
Проблема с этим подходом заключается в том, что теперь вы заблокировали себя проблемой модели, которая может наследовать только от одного другого класса, и, возможно, ваше решение таково, что вы все равно не можете использовать наследование для модели, которую вы намеревались.
Мое решение также начинается с базовой модели представления:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Затем я использую общую версию LayoutModel, которая наследуется от LayoutModel, например:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
С помощью этого решения я отключил необходимость наследования между макетной моделью и моделью.
Итак, теперь я могу использовать LayoutModel в Layout.cshtml следующим образом:
@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");
}
Почему бы вам просто не добавить новое частичное представление с собственным конкретным контроллером i, передавая требуемую модель в частичное представление, и, наконец, отрендерить упомянутое частичное представление в вашем Layout.cshtml с помощью RenderPartial или RenderAction?
Я использую этот метод для отображения информации о зарегистрированном пользователе, такой как имя, изображение профиля и т. Д.
старый вопрос, но просто чтобы упомянуть решение для разработчиков MVC5, вы можете использовать Model
свойство так же, как в представлении.
Model
Свойство как в целях и компоновках , ассоциированный с тем же ViewDataDictionary
объектом, так что вам не нужно делать какую - либо дополнительную работу , чтобы передать вашу модель на страницу макета, и вы не должны декларировать@model MyModelName
в макете.
Но обратите внимание, что при использовании @Model.XXX
в макете контекстное меню intelliSense не отображается, потому что Model
это динамический объект, аналогичный ViewBag
.
Возможно, это технически неправильный способ справиться с этим, но для меня самое простое и разумное решение - просто создать класс и создать его экземпляр в макете. Это единовременное исключение из правильного способа сделать это. Если это сделано больше, чем в макете, вам нужно серьезно переосмыслить то, что вы делаете, и, возможно, прочитать еще несколько руководств, прежде чем продолжить работу над своим проектом.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
тогда в представлении
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
в ядре .net вы даже можете пропустить это и использовать инъекцию зависимостей.
@inject My.Namespace.IMyLayoutModel myLayoutModel
Это одна из темных областей. Но, учитывая чрезвычайно сложные альтернативы, которые я вижу здесь, я думаю, что это более чем нормальное исключение, которое можно сделать во имя практичности. Особенно, если вы сделаете это простым и убедитесь, что любая тяжелая логика (я бы сказал, что ее действительно не должно быть, но требования разные) находится в другом классе / слое, которому она принадлежит. Это, безусловно, лучше, чем загрязнять ВСЕ ваши контроллеры или модели ради одного взгляда.
Есть еще один способ его заархивировать.
Просто реализуйте класс BaseController для всех контроллеров .
В BaseController
классе создайте метод, который возвращает класс модели, например.
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>
Предположим, ваша модель представляет собой набор объектов (или, может быть, один объект). Для каждого объекта в модели проделайте следующее.
1) Поместите объект, который вы хотите отобразить, в ViewBag. Например:
ViewBag.YourObject = yourObject;
2) Добавьте оператор using вверху _Layout.cshtml, который содержит определение класса для ваших объектов. Например:
@ using YourApplication.YourClasses;
3) Когда вы ссылаетесь на свой объект в _Layout, передайте его. Вы можете применить приведение из-за того, что вы сделали в (2).
public interface IContainsMyModel
{
ViewModel Model { get; }
}
public class ViewModel : IContainsMyModel
{
public string MyProperty { set; get; }
public ViewModel Model { get { return this; } }
}
public class Composition : IContainsMyModel
{
public ViewModel ViewModel { get; set; }
}
Используйте IContainsMyModel в своем макете.
Решено. Правило интерфейсов.
Например
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Подробнее о новой директиве @model