Apa yang saya lihat adalah properti Layout string. Tapi bagaimana saya bisa meneruskan model ke layout secara eksplisit?
Model
tersedia di _Layout
. Saya menggunakan MVC5.
Apa yang saya lihat adalah properti Layout string. Tapi bagaimana saya bisa meneruskan model ke layout secara eksplisit?
Model
tersedia di _Layout
. Saya menggunakan MVC5.
Jawaban:
Sepertinya Anda telah membuat model viewmodels Anda sedikit salah jika Anda mengalami masalah ini.
Secara pribadi saya tidak akan pernah mengetik halaman tata letak. Tetapi jika Anda ingin melakukannya, Anda harus memiliki model tampilan dasar yang diwarisi oleh model tampilan lain dan mengetik tata letak Anda ke model tampilan dasar dan halaman Anda ke model tampilan tertentu.
Contoh: Pengontrol:
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;
}
}
Contoh bagian atas Halaman Tata Letak
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Sekarang Anda dapat mereferensikan variabel 'viewModel' di halaman tata letak Anda dengan akses penuh ke objek yang diketik.
Saya menyukai pendekatan ini karena kontrolerlah yang mengontrol tata letak, sedangkan model tampilan halaman individual tetap agnostik tata letak.
Catatan untuk MVC Core
IActionFilter
dan melakukan pekerjaan yang sama persis di OnActionExecuting
. Masukan MyActionFilter
pada Anda 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;
}
}
}
ini adalah hal yang cukup mendasar, yang perlu Anda lakukan hanyalah membuat model tampilan dasar dan memastikan SEMUA! dan maksud saya SEMUA! dari tampilan Anda yang akan menggunakan tata letak itu akan menerima tampilan yang menggunakan model dasar itu!
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
di _Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
dalam metode Indeks (misalnya) di pengontrol rumah:
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">
Saya tidak setuju bahwa meneruskan model ke _layout adalah kesalahan, beberapa info pengguna dapat diteruskan dan data dapat diisi dalam rantai pewarisan pengontrol sehingga hanya satu implementasi yang diperlukan.
jelas untuk tujuan yang lebih maju, Anda harus mempertimbangkan untuk membuat kontrol statis kustom menggunakan injeksi dan menyertakan namespace model itu di _Layout.cshtml.
tetapi untuk pengguna dasar ini akan berhasil
Solusi umum adalah membuat model tampilan dasar yang berisi properti yang digunakan dalam file layout dan kemudian mewarisi dari model dasar ke model yang digunakan di halaman masing-masing.
Masalah dengan pendekatan ini adalah bahwa Anda sekarang telah mengunci diri Anda sendiri ke dalam masalah model yang hanya dapat mewarisi dari satu kelas lain, dan mungkin solusi Anda sedemikian rupa sehingga Anda tidak dapat menggunakan pewarisan pada model yang Anda inginkan.
Solusi saya juga dimulai dengan model tampilan dasar:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
Apa yang kemudian saya gunakan adalah versi umum dari LayoutModel yang diwarisi dari LayoutModel, seperti ini:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
Dengan solusi ini saya telah memutuskan kebutuhan memiliki warisan antara model tata letak dan model.
Jadi sekarang saya bisa melanjutkan dan menggunakan LayoutModel di Layout.cshtml seperti ini:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Dan di halaman Anda dapat menggunakan LayoutModel generik seperti ini:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
Dari pengontrol Anda, Anda cukup mengembalikan model tipe LayoutModel:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Mengapa Anda tidak menambahkan Partial View baru dengan kontroler spesifik milik saya yang meneruskan model yang diperlukan ke tampilan parsial dan akhirnya Render tampilan parsial yang disebutkan di Layout.cshtml Anda menggunakan RenderP Partial atau RenderAction?
Saya menggunakan metode ini untuk menampilkan info pengguna yang masuk seperti nama, gambar profil, dll.
pertanyaan lama tetapi hanya untuk menyebutkan solusi untuk pengembang MVC5, Anda dapat menggunakan Model
properti yang sama seperti yang terlihat.
The Model
properti di kedua tampilan dan tata letak assosiated dengan sama ViewDataDictionary
objek, sehingga Anda tidak harus melakukan kerja ekstra untuk melewati model Anda ke halaman tata letak, dan Anda tidak harus menyatakan @model MyModelName
dalam tata letak.
Tetapi perhatikan bahwa ketika Anda menggunakan @Model.XXX
dalam tata letak menu konteks intelliSense tidak akan muncul karena di Model
sini adalah objek dinamis seperti ViewBag
.
Mungkin secara teknis ini bukan cara yang tepat untuk menanganinya, tetapi solusi paling sederhana dan paling masuk akal bagi saya adalah dengan membuat kelas dan membuat instance-nya dalam tata letak. Ini adalah pengecualian satu kali untuk cara melakukannya yang benar. Jika ini dilakukan lebih dari pada tata letak maka Anda perlu memikirkan kembali secara serius apa yang Anda lakukan dan mungkin membaca beberapa tutorial lagi sebelum melanjutkan lebih jauh dalam proyek Anda.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
lalu dalam tampilan
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
di .net core Anda bahkan dapat melewati itu dan menggunakan injeksi ketergantungan.
@inject My.Namespace.IMyLayoutModel myLayoutModel
Ini adalah salah satu area yang agak teduh. Tetapi mengingat alternatif yang sangat rumit yang saya lihat di sini, saya pikir itu lebih dari sekadar pengecualian yang baik untuk dibuat atas nama kepraktisan. Terutama jika Anda memastikan untuk membuatnya tetap sederhana dan memastikan logika yang berat (saya berpendapat bahwa sebenarnya tidak boleh ada, tetapi persyaratan berbeda) ada di kelas / lapisan lain di mana tempatnya. Hal ini tentunya lebih baik daripada mencemari SEMUA pengontrol atau model Anda hanya untuk satu tampilan ..
Ada cara lain untuk mengarsipkannya.
Cukup terapkan kelas BaseController untuk semua pengontrol .
Di BaseController
kelas, buat metode yang mengembalikan kelas Model seperti misalnya.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layout
halaman Anda dapat memanggil metode ituGetTopMenu()
@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>
Anggaplah model Anda adalah kumpulan objek (atau mungkin satu objek). Untuk setiap objek dalam model, lakukan hal berikut.
1) Letakkan objek yang ingin Anda tampilkan di ViewBag. Sebagai contoh:
ViewBag.YourObject = yourObject;
2) Tambahkan pernyataan using di bagian atas _Layout.cshtml yang berisi definisi kelas untuk objek Anda. Sebagai contoh:
@ menggunakan YourApplication.YourClasses;
3) Ketika Anda mereferensikan yourObject di _Layout cast itu. Anda dapat menerapkan pemeran karena apa yang Anda lakukan di (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; }
}
Gunakan IContainsMyModel dalam tata letak Anda.
Terpecahkan. Aturan antarmuka.
Sebagai contoh
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Baca selengkapnya tentang direktif @model baru