Модель ASP.NET сдать в MVC бритвы для макета
то, что я вижу, это свойство макета строки. Но как я могу передать модель в макет явно?
10 ответов:
кажется, что вы смоделировали ваши viewmodels немного неправильно, если у вас есть эта проблема.
лично я бы никогда не набрал страницу макета. Но если вы хотите это сделать, у вас должна быть базовая viewmodel, которую наследуют ваши другие viewmodels, и введите свой макет в базовую viewmodel, а вы страницы в определенный раз.
- добавьте свойство к контроллеру (или базовому контроллеру) под названием 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 Core
Ядро Mvc, похоже, сдувает содержимое 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; } } }
это довольно простой материал, все, что вам нужно сделать, это создать базовую модель представления и убедитесь, что все! и я имею в виду все! из ваших представлений, которые когда-либо будут использовать этот макет, будут получать представления, которые используют эту базовую модель!
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...
в методе индекса (например) в домашнем контроллере:
public ActionResult Index() { var model = new SomeViewModel() { }; return View(model); }
индекс.cshtml:
@model Models.SomeViewModel @{ ViewBag.Title = "Title"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="row">
Я не согласен, что передача модели в _layout-это ошибка, некоторая информация о пользователе может быть передан, и данные могут быть заполнены в цепочке наследования контроллеров, поэтому требуется только одна реализация.
очевидно, для более продвинутых целей вы должны рассмотреть возможность создания пользовательского статического contaxt с помощью инъекции и включить это пространство имен модели в _Layout.cshtml.
но для простых пользователей это будет делать трюк
Почему бы вам просто не добавить новый частичный вид с собственным конкретным контроллером i, передающим требуемую модель в частичный вид и, наконец, визуализировать упомянутый частичный вид на вашем макете.cshtml с помощью RenderPartial или RenderAction ?
Я использую этот метод для отображения зарегистрированной информации пользователя, такой как имя , изображение профиля и т. д.
общим решением является создание базовой модели представления, которая содержит свойства, используемые в файле макета, а затем наследует от базовой модели к моделям, используемым на соответствующих страницах.
проблема с этим подходом заключается в том, что теперь вы заперли себя в проблеме модель может наследовать только от одного класса, и, возможно, ваше решение, что вы не можете использовать наследование для модели, предназначенной в любом случае.
мое решение также начинается с базы вид модели:
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 в макете.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"); }
возможно, это технически не правильный способ справиться с этим, но самое простое и разумное решение для меня-просто создать класс и создать его экземпляр в макете. Это однократное исключение из другого правильного способа сделать это. Если это сделано больше, чем в макете, то вам нужно серьезно переосмыслить то, что вы делаете, и, возможно, прочитать еще несколько учебников, прежде чем продвигаться дальше в своем проекте.
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
Это одна из тех областей, которая является своего рода теневой. Но учитывая чрезвычайно сложные альтернативы, которые я вижу здесь, я думаю, что это более чем нормальное исключение, чтобы сделать во имя практичности. Особенно если вы убедитесь, что это просто и убедитесь, что любая тяжелая логика (я бы сказал, что ее действительно не должно быть, но требования отличаются) находится в другом классе/слое, где она принадлежит. Это конечно лучше, чем загрязнять все ваши контроллеры или модели ради в основном только одного представления..
старый вопрос, но просто упомянуть решение для разработчиков MVC5, вы можете использовать
Model
свойство такое же, как и в представлении.The
Model
свойство в представлении и макете ассоциируется с тем жеViewDataDictionary
объект, поэтому вам не нужно делать никаких дополнительных работ, чтобы передать вашу модель на страницу макета, и вам не нужно объявлять@model MyModelName
в макете.но обратите внимание, что при использовании
@Model.XXX
в макете контекстное меню intelliSense не появится, так какModel
вот динамический объект так же, какViewBag
.
предположим, что ваша модель представляет собой набор объектов (или, возможно, один объект). Для каждого объекта в модели, выполните следующие действия.
1) поместите объект, который вы хотите отобразить в ViewBag. Например:
ViewBag.YourObject = yourObject;
2) Добавьте оператор using в верхней части _Layout.cshtml, который содержит определение класса объектов. Например:
@С помощью YourApplication.Ваши классы;
3) Когда вы ссылаетесь на yourObject в _Layout cast it. Вы можете примените приведение из-за того, что вы сделали в (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 директива