Що я бачу, це властивість Layout string. Але як я можу явно передати модель на макет?
Model
доступно в _Layout
. Я використовую MVC5.
Що я бачу, це властивість Layout string. Але як я можу явно передати модель на макет?
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
класі створіть метод, який повертає клас Model, наприклад,
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) Додайте використовувальний оператор у верхній частині _Layout.cshtml, який містить визначення класу для ваших об'єктів. Наприклад:
@ використовуючи 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