Pertanyaan Silet Nested Layouts dengan Cascading Sections


Saya memiliki situs MVC3 menggunakan Razor sebagai mesin pandangannya. Saya ingin situs saya menjadi skinnable. Sebagian besar kulit yang tersedia cukup mirip sehingga dapat berasal dari tata letak master bersama.

Oleh karena itu, saya mempertimbangkan desain ini:

Planned view diagram

Namun, saya ingin dapat menelepon RenderSection di lapisan bawah, _Common.cshtml, dan membuatnya merender bagian yang didefinisikan di lapisan atas, Detail.cshtml. Ini tidak berfungsi: RenderSection rupanya hanya membuat bagian yang didefinisikan lapisan berikutnya.

Tentu saja, saya dapat mendefinisikan setiap bagian di setiap kulit. Misalnya, jika _Common perlu menelepon RenderSection("hd") untuk bagian yang ditentukan dalam Detail, Saya hanya menempatkan ini di masing-masing _Skin dan itu berhasil:

@section hd {
    @RenderSection("hd")
}

Ini menghasilkan duplikasi kode (karena setiap kulit harus memiliki bagian yang sama) dan umumnya terasa berantakan. Saya masih baru di Razor, dan sepertinya saya mungkin kehilangan sesuatu yang jelas.

Ketika melakukan debug, saya dapat melihat daftar lengkap dari bagian yang ditentukan di WebViewPage.SectionWritersStack. Jika saya bisa memberitahu RenderSection untuk melihat seluruh daftar sebelum menyerah, itu akan menemukan bagian yang saya butuhkan. Sayangnya, SectionWritersStack adalah non-publik.

Atau, jika saya dapat mengakses hierarki halaman tata letak dan percobaan eksekusi RenderSection di setiap konteks yang berbeda, saya dapat menemukan bagian yang saya perlukan. Saya mungkin kehilangan sesuatu, tetapi saya tidak melihat cara apa pun untuk melakukan ini.

Adakah cara untuk mencapai tujuan ini, selain metode yang sudah saya uraikan?


76
2018-04-02 20:16


asal


Jawaban:


Ini sebenarnya tidak mungkin hari ini menggunakan API publik (selain menggunakan pendekatan redefinisi bagian). Anda mungkin memiliki sedikit keberuntungan menggunakan refleksi pribadi tetapi itu tentu saja adalah pendekatan yang rapuh. Kami akan melihat untuk membuat skenario ini lebih mudah dalam versi Razor berikutnya.

Sementara itu, inilah beberapa posting blog yang saya tulis tentang masalah ini:


35
2018-04-03 04:48



@helper ForwardSection( string section )
{
   if (IsSectionDefined(section))
   {
       DefineSection(section, () => Write(RenderSection(section)));
   }
}

Apakah ini akan melakukan pekerjaan itu?


16
2017-10-15 21:37



Saya tidak yakin apakah ini mungkin dalam MVC 3 tetapi di MVC 5 saya berhasil melakukan ini dengan menggunakan trik berikut:

Di ~/Views/Shared/_Common.cshtml tulis kode HTML umum Anda seperti:

<!DOCTYPE html>
<html lang="fa">
<head>
    <title>Skinnable - @ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

Di ~/Views/_ViewStart.cshtml:

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

Sekarang yang harus Anda lakukan adalah menggunakan _Common.cshtml sebagai Layout untuk semua kulit. Misalnya, di ~/Views/Shared/Skin1.cshtml:

@{
    Layout = "~/Views/Shared/_Common.cshtml";
}

<p>Something specific to Skin1</p>

@RenderBody()

Sekarang Anda dapat mengatur kulit sebagai tata letak dalam pengontrol atau tampilan berdasarkan kriteria Anda. Sebagai contoh:

    public ActionResult Index()
    {
        //....
        if (user.SelectedSkin == Skins.Skin1)
            return View("ViewName", "Skin1", model);
    }

Jika Anda menjalankan kode di atas, Anda harus mendapatkan halaman HTML dengan kedua konten tersebut Skin1.cshtml dan _Common.cshtml

Singkatnya, Anda akan mengatur tata letak untuk halaman tata letak (kulit).


4
2017-12-29 15:13



Tidak yakin apakah ini akan membantu Anda, tetapi saya menulis beberapa metode ekstensi untuk membantu bagian "menggelembung" dari dalam parsial, yang seharusnya berfungsi untuk tata letak yang disarangkan juga.

Menyuntikkan konten ke dalam bagian tertentu dari tampilan parsial ASP.NET MVC 3 dengan Razor View Engine

Deklarasikan dalam tata letak / tampilan / parsial anak

@using (Html.Delayed()) {
    <b>show me multiple times, @Model.Whatever</b>
}

Berikan pada orang tua mana pun

@Html.RenderDelayed();

Lihat tautan jawaban untuk lebih banyak kasus penggunaan, seperti hanya menampilkan satu blok yang tertunda bahkan jika dinyatakan dalam tampilan berulang, menampilkan blok tertunda tertentu, dll.


1
2017-12-09 20:46