สิ่งที่ฉันเห็นคือคุณสมบัติเค้าโครงสตริง แต่ฉันจะส่งแบบจำลองไปจัดวางอย่างชัดเจนได้อย่างไร
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...
ในวิธี 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");
}
ทำไมคุณไม่เพิ่มมุมมองบางส่วนใหม่ด้วยคอนโทรลเลอร์เฉพาะของฉันเองโดยส่งโมเดลที่ต้องการไปยังมุมมองบางส่วนและในที่สุดก็แสดงมุมมองบางส่วนที่กล่าวถึงบน Layout.cshtml ของคุณโดยใช้ RenderPartial หรือ RenderAction
ฉันใช้วิธีนี้เพื่อแสดงข้อมูลของผู้ใช้ที่ล็อกอินเช่นชื่อรูปโปรไฟล์และอื่น ๆ
คำถามเก่า แต่พูดถึงวิธีแก้ปัญหาสำหรับนักพัฒนา MVC5 คุณสามารถใช้Model
คุณสมบัติเดียวกับในมุมมอง
Model
คุณสมบัติทั้งในมุมมองและรูปแบบเป็น assosiated ด้วยเหมือนกัน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 core คุณสามารถข้ามสิ่งนั้นและใช้การฉีดพึ่งพาได้
@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) เมื่อคุณอ้างอิง yourObject ใน _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ใหม่