Bố cục lồng nhau bằng dao cạo với các phần xếp tầng


80

Tôi có một trang web MVC3 sử dụng Razor làm công cụ xem của nó. Tôi muốn trang web của mình có thể lột được. Hầu hết các giao diện có thể có đủ tương tự để chúng có thể lấy từ một bố cục chính được chia sẻ.

Do đó, tôi đang xem xét thiết kế này:

Sơ đồ chế độ xem có kế hoạch

Tuy nhiên, tôi muốn có thể gọi RenderSectionở lớp dưới cùng _Common.cshtmlvà để nó hiển thị một phần được xác định ở lớp trên cùng Detail.cshtml,. Điều này không hoạt động: RenderSectiondường như chỉ hiển thị các phần được xác định ở lớp tiếp theo.

Tất nhiên, tôi có thể xác định từng phần trong mỗi skin. Ví dụ: nếu _Commoncần gọi RenderSection("hd")một phần được xác định trong Detail, tôi chỉ cần đặt phần này vào mỗi phần _Skinvà nó hoạt động:

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

Điều này dẫn đến một số mã trùng lặp (vì mỗi skin bây giờ phải có cùng một phần này) và thường cảm thấy lộn xộn. Tôi vẫn còn mới với Razor, và có vẻ như tôi có thể thiếu một cái gì đó rõ ràng.

Khi gỡ lỗi, tôi có thể thấy danh sách đầy đủ các phần được xác định trong WebViewPage.SectionWritersStack. Nếu tôi có thể yêu cầu RenderSection xem qua toàn bộ danh sách trước khi từ bỏ, nó sẽ tìm thấy phần tôi cần. Than ôi, SectionWritersStack là không công khai.

Ngoài ra, nếu tôi có thể truy cập hệ thống phân cấp của các trang bố cục và cố gắng thực thi RenderSection trong từng ngữ cảnh khác nhau, tôi có thể tìm thấy phần tôi cần. Tôi có lẽ đang thiếu một cái gì đó, nhưng tôi không thấy bất kỳ cách nào để làm điều này.

Có cách nào để thực hiện mục tiêu này, ngoài phương pháp tôi đã vạch ra không?

Câu trả lời:


35

Trên thực tế, điều này không thể thực hiện được ngày nay bằng cách sử dụng API công khai (ngoài việc sử dụng phương pháp xác định lại phần). Bạn có thể gặp một số may mắn khi sử dụng phản ánh riêng tư nhưng đó tất nhiên là một cách tiếp cận mong manh. Chúng tôi sẽ xem xét việc làm cho kịch bản này dễ dàng hơn trong phiên bản tiếp theo của Razor.

Trong khi chờ đợi, đây là một vài bài đăng trên blog mà tôi đã viết về chủ đề này:


3
Cảm ơn bạn đã phản hồi, tôi đã chơi với các Phần lồng nhau bằng cú pháp này (như ở trên): @section hd {@RenderSection ("hd")} ... thực sự hoạt động với tôi và có vẻ như tôi có thể sao chép các Trang chủ lồng nhau hiện có . Tôi nghĩ rằng tôi đã hiểu sai câu hỏi một chút và nghĩ rằng điều này sẽ không hiệu quả.
Mark Redman

2
Cả câu hỏi và câu trả lời đã giúp ích rất nhiều và tôi cũng đồng ý rằng điều này sẽ được thực hiện dễ dàng hơn trong phiên bản tiếp theo của Razor. Và bạn cũng nên kích hoạt khả năng các dạng xem một phần cũng có thể triển khai các phần, tính năng này hiện không được hỗ trợ.
mare

1
@Shrike Tôi không nghĩ có gì thay đổi trong lĩnh vực này. Bạn có thể nhập yêu cầu tính năng trên trang web uservoice hoặc lỗi trên CodePlex
marcind

1
@marcind Hãy xem câu trả lời của tôi. Tôi nghĩ đây là những gì OP yêu cầu. Đúng?
Alireza Noori

1
MVC 5 đã hết. Bất kỳ bản cập nhật? Alirzea cho biết anh đã tìm ra giải pháp, nhưng nó dường như không phù hợp với vấn đề OP vì nó không tham chiếu đến các phần.
Snekse

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

Điều này sẽ thực hiện công việc?


Bạn có đang sử dụng cái này trong lớp trung gian không? Khá giống với lớp mở rộng này ? Nếu vậy, điều này sẽ thuận tiện hơn khi khai báo lại một phần, hơn là giải quyết vấn đề, phải không? Chỉ cần chắc chắn rằng tôi hiểu, vì tôi đến muộn với cuộc thảo luận này.
drzaus

Đối với tôi, đây là giải pháp duy nhất có hiệu quả. Nếu một phần được hiển thị có điều kiện trong bố cục cơ sở, MVC sẽ gây ra lỗi thời gian chạy trừ khi phần đó được xác định có điều kiện (như thế này) trong lớp trung gian. Cảm ơn @Randy!
Michael

Có thể chuyển tiếp tất cả các phần hiện được xác định không?
nvirth

4

Tôi không chắc liệu điều này có thể thực hiện được trong MVC 3 hay không nhưng trong MVC 5, tôi có thể thực hiện điều này thành công bằng thủ thuật sau:

Trong ~/Views/Shared/_Common.cshtmlghi của bạn HTML thông thường mã như:

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

Trong ~/Views/_ViewStart.cshtml:

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

Bây giờ tất cả những gì bạn phải làm là sử dụng _Common.cshtmllàm Layoutgiao diện cho tất cả các giao diện. Ví dụ, trong ~/Views/Shared/Skin1.cshtml:

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

<p>Something specific to Skin1</p>

@RenderBody()

Bây giờ bạn có thể đặt da làm bố cục của mình trong bộ điều khiển hoặc chế độ xem dựa trên tiêu chí của bạn. Ví dụ:

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

Nếu bạn chạy mã trên, bạn sẽ nhận được một trang HTML có cả nội dung của Skin1.cshtml_Common.cshtml

Tóm lại, bạn sẽ thiết lập bố cục cho trang bố cục (skin).


Tôi gặp sự cố với cách tiếp cận này vì các phần sẽ không hiển thị. Tôi tìm thấy giải pháp tại blogs.msdn.microsoft.com/marcinon/2010/12/15/...
Spikolynn

1

Không chắc liệu điều này có giúp ích được cho bạn hay không, nhưng tôi đã viết một số phương pháp mở rộng để giúp "tạo bong bóng" các phần từ bên trong các phần tử, cũng sẽ hoạt động cho các bố cục lồng nhau.

Đưa nội dung vào các phần cụ thể từ chế độ xem một phần ASP.NET MVC 3 với Razor View Engine

Khai báo trong bố cục con / xem / một phần

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

Hiển thị trong bất kỳ phụ huynh nào

@Html.RenderDelayed();

Xem liên kết câu trả lời để biết thêm các trường hợp sử dụng, chẳng hạn như chỉ hiển thị một khối bị trì hoãn ngay cả khi được khai báo trong chế độ xem lặp lại, hiển thị các khối bị trì hoãn cụ thể, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.