To, co widzę, to właściwość układu ciągu. Ale jak mogę jawnie przekazać model do układu?
Modeljest 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?
Modeljest 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
IActionFilteri wykonywanie dokładnie tej samej pracy w OnActionExecuting. Załóż MyActionFilterswó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 Modelsamej właściwości co w widoku.
ModelNieruchomość zarówno widok i układ jest assosiated z tego samego ViewDataDictionaryobiektu, więc nie trzeba wykonywać żadnych dodatkowych prac przekazać swój model na stronie układu, a nie trzeba zadeklarować @model MyModelNamew układzie.
Zauważ jednak, że gdy używasz @Model.XXXw układzie, menu kontekstowe intelliSense nie pojawi się, ponieważ Modeltutaj 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 BaseControllerklasie 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; }
Layoutstronie 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