내가 보는 것은 문자열 레이아웃 속성입니다. 하지만 어떻게 모델을 레이아웃에 명시 적으로 전달할 수 있습니까?
Model
에서 사용할 수 있습니다 _Layout
. MVC5를 사용하고 있습니다.
내가 보는 것은 문자열 레이아웃 속성입니다. 하지만 어떻게 모델을 레이아웃에 명시 적으로 전달할 수 있습니까?
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...
홈 컨트롤러의 인덱스 (예 :) 메소드에서 :
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에 포함해야합니다.
그러나 기본 사용자에게는 이것이 트릭을 할 것입니다.
일반적인 해결책은 레이아웃 파일에 사용 된 속성을 포함하는 기본보기 모델을 만든 다음 기본 모델에서 각 페이지에서 사용되는 모델로 상속하는 것입니다.
이 접근 방식의 문제는 이제 모델의 문제가 다른 하나의 클래스에서만 상속 할 수 있다는 문제에 잠겨 있다는 것이며, 어쨌든 의도 한 모델에서 상속을 사용할 수없는 솔루션 일 수 있습니다.
내 솔루션은 기본 뷰 모델로 시작됩니다.
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; }
}
이 솔루션을 통해 레이아웃 모델과 모델 간의 상속 필요성을 분리했습니다.
이제 다음과 같이 Layout.cshtml에서 LayoutModel을 사용할 수 있습니다.
@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");
}
필요한 모델을 부분보기에 전달하는 고유 한 컨트롤러로 새 부분보기를 추가하고 마지막으로 RenderPartial 또는 RenderAction을 사용하여 Layout.cshtml에서 언급 된 부분보기를 렌더링하지 않는 이유는 무엇입니까?
이 방법을 사용하여 이름, 프로필 사진 등과 같은 로그인 한 사용자의 정보를 표시합니다.
기술적으로는 그것을 처리하는 적절한 방법이 아닐 수도 있지만, 가장 간단하고 합리적인 해결책은 클래스를 만들고 레이아웃에서 인스턴스화하는 것입니다. 그렇지 않으면 올바른 방법에 대한 일회성 예외입니다. 이것이 레이아웃보다 더 많이 수행된다면, 당신이하는 일을 진지하게 재고하고 프로젝트를 더 진행하기 전에 몇 가지 튜토리얼을 더 읽어야합니다.
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
예를 들어 class 같은 모델 클래스를 반환하는 메서드를 만듭니다.
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 맨 위에 using 문을 추가합니다. 예를 들면 :
@using YourApplication.YourClasses;
3) _Layout에서 yourObject를 참조 할 때 캐스팅합니다. (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 지시문 에 대해 자세히 알아보기