То, что я вижу, это свойство макета строки. Но как я могу явно передать модель в макет?
Модель ASP.NET MVC Razor для макета
Ответ 1
Похоже, вы немного поправили свои модели просмотра, если у вас есть эта проблема.
Лично я бы никогда не набирал страницу макета. Но если вы хотите сделать это, у вас должна быть базовая модель просмотра, которую наследуют ваши другие модели viewmodel, и введите ваш макет в базовую модель просмотра и ваши страницы до определенного раза.
Ответ 2
- Добавить свойство в ваш контроллер (или базовый контроллер), называемый MainLayoutViewModel (или любой другой) с любым типом, который вы хотели бы использовать.
- В конструкторе вашего контроллера (или базового контроллера) создайте экземпляр типа и установите его в свойство.
- Установите его в поле ViewData (или ViewBag)
- На странице "Макет" добавьте это свойство в свой тип.
Пример: Контроллер:
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
Mvc Core, похоже, сбрасывает содержимое ViewData/ViewBag после вызова каждого действия в первый раз. Это означает, что назначение ViewData в конструкторе не работает. Тем не менее, что работает, используется
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;
}
}
}
Ответ 3
Это довольно простой материал, все, что вам нужно сделать, это создать модель базового представления и убедиться, что ALL! и я имею в виду ВСЕ! ваших просмотров, которые когда-либо будут использовать этот макет, получат представления, которые используют эту базовую модель!
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 является ошибкой, некоторая информация пользователя может быть передана и данные могут быть заполнены в цепочке наследования контроллеров, поэтому необходима только одна реализация.
очевидно, для более продвинутой цели вам следует подумать о создании настраиваемого статического contaxt с помощью инъекции и включить это пространство имен модели в _Layout.cshtml.
но для основных пользователей это сделает трюк
Ответ 4
Почему бы вам просто не добавить новый Partial View с собственным контроллером, передающим требуемую модель в частичный вид и, наконец, отобразить упомянутый частичный вид вашего Layout.cshtml с помощью RenderPartial или RenderAction?
Я использую этот метод для отображения зарегистрированной информации пользователя, такой как имя, изображение профиля и т.д.
Ответ 5
Общим решением является создание модели базового представления, которая содержит свойства, используемые в файле макета, а затем наследует от базовой модели модели, используемые на соответствующих страницах.
Проблема с этим подходом заключается в том, что теперь вы заблокировали себя в проблеме модели, которая может наследовать только один класс, и, может быть, ваше решение таково, что вы не можете использовать наследование для модели, которую вы планировали в любом случае.
Мое решение также начинается с базовой модели:
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");
}
Ответ 6
Возможно, это не технически правильный способ справиться с этим, но самое простое и разумное решение для меня - просто создать класс и создать его в макете. Это одноразовое исключение, в противном случае правильный способ сделать это. Если это делается больше, чем в макете, вам необходимо серьезно пересмотреть то, что вы делаете, и, возможно, прочитать еще несколько руководств, прежде чем продвигаться дальше в своем проекте.
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
Это одна из тех областей, которые являются теневыми. Но, учитывая чрезвычайно сложные альтернативы, которые я вижу здесь, я думаю, что это более чем исключение, сделанное во имя практичности. Особенно, если вы убедитесь, что это просто и убедитесь, что любая тяжелая логика (я бы сказал, что там действительно не должно быть никаких, но требования различаются) находится в другом классе/слое, где он принадлежит. Это, безусловно, лучше, чем загрязнение ВСЕХ ваших контроллеров или моделей ради всего лишь одного взгляда.
Ответ 7
старый вопрос, но, чтобы упомянуть решение для разработчиков MVC5, вы можете использовать свойство Model
так же, как и в представлении.
Свойство Model
как в представлении, так и в макете ассоциируется с одним и тем же объектом ViewDataDictionary
, поэтому вам не нужно выполнять какую-либо дополнительную работу, чтобы передать вашу модель на страницу макета, и вам не нужно объявите @model MyModelName
в макете.
Но обратите внимание, что при использовании @Model.XXX
в макете контекстное меню intelliSense не будет отображаться, потому что Model
здесь является динамическим объектом, как ViewBag
.
Ответ 8
Предположим, что ваша модель представляет собой набор объектов (или, возможно, один объект). Для каждого объекта в модели сделайте следующее.
1) Поместите объект, который вы хотите отобразить в ViewBag. Например:
ViewBag.YourObject = yourObject;
2) Добавьте оператор using вверху _Layout.cshtml, который содержит определение класса для ваших объектов. Например:
@using YourApplication.YourClasses;
3) Когда вы ссылаетесь на свой объект в _Layout, произведите его. Вы можете применить бросок из-за того, что вы сделали в (2).
Ответ 9
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 в своем макете.
решаемая. Правила интерфейсов.
Ответ 10
Например
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Подробнее о новой директиве @