Модель ASP.NET сдать в MVC бритвы для макета


то, что я вижу, это свойство макета строки. Но как я могу передать модель в макет явно?

10 79

10 ответов:

кажется, что вы смоделировали ваши viewmodels немного неправильно, если у вас есть эта проблема.

лично я бы никогда не набрал страницу макета. Но если вы хотите это сделать, у вас должна быть базовая viewmodel, которую наследуют ваши другие viewmodels, и введите свой макет в базовую viewmodel, а вы страницы в определенный раз.

  1. добавьте свойство к контроллеру (или базовому контроллеру) под названием MainLayoutViewModel (или что-то еще) с любым типом, который вы хотели бы использовать.
  2. в конструкторе вашего контроллера (или базового контроллера) создайте экземпляр типа и установите его в свойство.
  3. установите его в поле ViewData (или ViewBag)
  4. на странице макета приведите это свойство к вашему типу.

пример: Контроллер:

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 директива