Модель 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";
}

Подробнее о новой директиве @