To, co widzę, to właściwość układu ciągu. Ale jak mogę jawnie przekazać model do układu?
Model
jest dostępny w _Layout
. Używam MVC5.
To, co widzę, to właściwość układu ciągu. Ale jak mogę jawnie przekazać model do układu?
Model
jest dostępny w _Layout
. Używam MVC5.
Odpowiedzi:
Wygląda na to, że modelowałeś swoje modele widoków trochę źle, jeśli masz ten problem.
Osobiście nigdy nie napisałbym strony układu. Ale jeśli chcesz to zrobić, powinieneś mieć podstawowy model widoku, z którego dziedziczą inne modele widoku, i wpisz układ do podstawowego modelu widoku, a strony do określonego raz.
Przykład: kontroler:
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;
}
}
Przykładowa góra strony układu
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Teraz możesz odwołać się do zmiennej „viewModel” na swojej stronie układu z pełnym dostępem do wpisanego obiektu.
Podoba mi się to podejście, ponieważ to kontroler kontroluje układ, podczas gdy poszczególne modele widoku strony pozostają niezależne od układu.
Uwagi dotyczące MVC Core
IActionFilter
i wykonywanie dokładnie tej samej pracy w OnActionExecuting
. Załóż MyActionFilter
swój 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;
}
}
}
to jest dość podstawowa rzecz, wszystko, co musisz zrobić, to utworzyć model widoku podstawowego i upewnić się, że WSZYSTKIE! i mam na myśli WSZYSTKIE! Twoich widoków, które kiedykolwiek będą używać tego układu, otrzymają widoki korzystające z tego modelu podstawowego!
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
w _Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
w metodzie Index (na przykład) w kontrolerze domowym:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
plik Index.cshtml:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
Nie zgadzam się, że przekazanie modelu do _layout jest błędem, niektóre informacje o użytkowniku mogą zostać przekazane, a dane mogą zostać wypełnione w łańcuchu dziedziczenia kontrolerów, więc potrzebna jest tylko jedna implementacja.
oczywiście dla bardziej zaawansowanych celów należy rozważyć utworzenie niestandardowego kontekstu statycznego przy użyciu wstrzykiwania i dołączyć tę przestrzeń nazw modelu do pliku _Layout.cshtml.
ale dla zwykłych użytkowników to wystarczy
Typowym rozwiązaniem jest utworzenie modelu widoku bazowego, który zawiera właściwości używane w pliku układu, a następnie dziedziczenie z modelu podstawowego do modeli używanych na odpowiednich stronach.
Problem z tym podejściem polega na tym, że teraz zamknąłeś się w problemie, że model może dziedziczyć tylko z jednej innej klasy, a być może Twoje rozwiązanie jest takie, że nie możesz i tak używać dziedziczenia w modelu, który zamierzałeś.
Moje rozwiązanie również zaczyna się od modelu widoku podstawowego:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Następnie używam ogólnej wersji LayoutModel, która dziedziczy po LayoutModel, na przykład:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
Dzięki temu rozwiązaniu wyłączyłem konieczność dziedziczenia między modelem układu a modelem.
Więc teraz mogę iść dalej i użyć LayoutModel w Layout.cshtml w następujący sposób:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Na stronie możesz użyć ogólnego modelu LayoutModel w następujący sposób:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Ze swojego kontrolera po prostu zwracasz model typu LayoutModel:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Dlaczego po prostu nie dodasz nowego widoku częściowego z własnym, określonym kontrolerem, przekazując wymagany model do widoku częściowego i ostatecznie renderuj wspomniany widok częściowy na swoim Layout.cshtml za pomocą RenderPartial lub RenderAction?
Używam tej metody do wyświetlania informacji o zalogowanym użytkowniku, takich jak imię i nazwisko, zdjęcie profilowe itp.
stare pytanie, ale żeby wspomnieć o rozwiązaniu dla programistów MVC5, możesz użyć tej Model
samej właściwości co w widoku.
Model
Nieruchomość zarówno widok i układ jest assosiated z tego samego ViewDataDictionary
obiektu, więc nie trzeba wykonywać żadnych dodatkowych prac przekazać swój model na stronie układu, a nie trzeba zadeklarować @model MyModelName
w układzie.
Zauważ jednak, że gdy używasz @Model.XXX
w układzie, menu kontekstowe intelliSense nie pojawi się, ponieważ Model
tutaj jest obiektem dynamicznym, tak jak ViewBag
.
Może z technicznego punktu widzenia nie jest to właściwy sposób radzenia sobie z tym, ale dla mnie najprostszym i najbardziej rozsądnym rozwiązaniem jest utworzenie klasy i utworzenie jej instancji w układzie. Jest to jednorazowy wyjątek od prawidłowego sposobu wykonania tego. Jeśli jest to zrobione częściej niż w układzie, musisz poważnie przemyśleć to, co robisz, i może przeczytać jeszcze kilka samouczków, zanim przejdziesz dalej w swoim projekcie.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
wtedy w widoku
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
w .net core można to nawet pominąć i użyć iniekcji zależności.
@inject My.Namespace.IMyLayoutModel myLayoutModel
To jeden z tych obszarów, które są trochę zacienione. Ale biorąc pod uwagę niezwykle skomplikowane alternatywy, które tutaj widzę, myślę, że jest to więcej niż dobry wyjątek w imię praktyczności. Zwłaszcza jeśli upewnisz się, że jest to proste i upewnij się, że każda ciężka logika (argumentowałbym, że tak naprawdę nie powinno być, ale wymagania się różnią) znajduje się w innej klasie / warstwie, do której należy. Jest to z pewnością lepsze niż zanieczyszczanie WSZYSTKICH kontrolerów lub modeli ze względu na w zasadzie tylko jeden widok.
Istnieje inny sposób archiwizacji.
Wystarczy zaimplementować klasę BaseController dla wszystkich kontrolerów .
W BaseController
klasie utwórz metodę, która zwraca klasę Model, jak na przykład.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layout
stronie możesz wywołać tę metodę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>
Załóżmy, że Twój model jest zbiorem obiektów (lub może pojedynczym obiektem). Dla każdego obiektu w modelu wykonaj następujące czynności.
1) Umieść obiekt, który chcesz wyświetlić w ViewBag. Na przykład:
ViewBag.YourObject = yourObject;
2) Dodaj instrukcję using na górze _Layout.cshtml, która zawiera definicję klasy dla twoich obiektów. Na przykład:
@using YourApplication.YourClasses;
3) Kiedy odwołujesz się do obiektu yourObject w _Layout, rzutuj go. Możesz zastosować obsadę dzięki temu, co zrobiłeś w (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; }
}
Użyj IContainsMyModel w swoim układzie.
Rozwiązany. Reguła dotycząca interfejsów.
Na przykład
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Przeczytaj więcej o nowej dyrektywie @model