MVC 3 Razor, помощники с пользовательской разметкой / разделом

Я даже не уверен, возможно ли это, но я решил проверить, есть ли способ сделать это проще.

Во-первых, у меня есть несколько разметок на моем сайте, которые выглядят так:

<div class="module">
    <h3>Title</h3>
    <div>
        <p>Information goes here</p>
    </div>
</div>

То, что я хочу сделать, это обернуть это в какой-то вспомогательный / раздел, чтобы я мог сделать что-то вроде этого

@MyHelper("This is my Title") {
    <p>Here is my custom markup</p>
}

Затем, когда он рендерится, он вставит заголовок, переданный через параметр между <h3></h3> и пользовательская разметка в div. Пользовательская разметка может быть любой: от теста, до элементов управления, до частичного представления. Это то, что возможно?

4 ответа

Решение

Что ж, вот "стандартный" способ сделать что-то близкое к нему, используя вспомогательное расширение HTML. Очень простая версия того, что Html.BeginForm() делает.

Подход: просто верните IDisposable, и пусть using Заявление позаботится об остальном.

Это всего лишь пример концепции (хотя она работает). Не предназначен для немедленного повторного использования. Написан быстро с большим количеством ярлыков, а не с рабочим кодом, множеством возможностей для улучшения и оптимизации, может иметь глупые ошибки, может использовать TagBuilder и т. Д. И т. Д. Может быть легко изменен для повторного использования класса Wrapper для различных... оберток (может даже быть универсальным уже в ASP.NET MVC - не было необходимости в этом).

public static class WrapHelper
{
    private class Wrapper : IDisposable
    {
        private bool disposed;
        private readonly TextWriter writer;

        public Wrapper(HtmlHelper html)
        {
            this.writer = html.ViewContext.Writer;
        }

        public void Dispose()
        {
            if (disposed) return;

            disposed = true;

            writer.WriteLine("  </div>");
            writer.WriteLine("</div>");
        }
    }

    public static IDisposable Wrap(this HtmlHelper html, string title)
    {
        TextWriter writer = html.ViewContext.Writer;

        writer.WriteLine("<div class=\"module\">");
        writer.WriteLine("  <h3>" + html.Encode(title) + "</h3>");
        writer.WriteLine("  <div>");

        return new Wrapper(html);
    }
}

Использование:

@using (Html.Wrap("Title"))
{
    <p>My very own markup.</p>
}

Есть и другой способ, без одноразового трюка, который также требует немного меньше работы, отлично подходит для маленьких помощников.

@helper MyHelper(string title, Func<object, object> markup) {
    <div class="module">
        <h3>Title</h3>
        <div>
            <p>@markup.DynamicInvoke(this.ViewContext)</p>
        </div>
    </div>
}

Использование этого помощника выглядит так:

@MyHelper("This is my Title", 
    @<p>Here is my custom markup</p>
)

Или с несколькими строками:

@MyHelper("This is my Title", 
    @<text>
        <p>More than one line</p>
        <p>Of markup</p>
    </text>
)

Элементы управления Telerik MVC использовали этот трюк, например, чтобы вы могли добавить свой код JavaScript при загрузке документа.

Вот также хороший пример. Здесь также есть некоторая информация.

@TheKaneda, спасибо за понимание. Я взял вашу идею и расширил ее так, чтобы вы указали имя PartialView, и оно знает, как его проанализировать.

<Extension()> _
Public Function UseTemplate(ByVal html As HtmlHelper, ByVal PartialView As String) As IDisposable
    Return New TemplateWrapper(html, PartialView)
End Function

Public Class TemplateWrapper
    Implements IDisposable

    Private _HtmlHelper As HtmlHelper

    'Index 0 is header
    'Index 1 is footer
    Private _TemplateWrapper As String()

    Public Sub New(ByVal Html As HtmlHelper, ByVal PartialView As String)

        _TemplateWrapper = Html.Partial(PartialView).ToHtmlString.Split("@@RenderBody()")

        _HtmlHelper = Html
        _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(0))

    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose

        _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(1).Substring(12))

    End Sub

End Class

Используйте то же использование, что и в примере @ TheKaneda. В вашем частичном представлении вместо вызова @RenderBody () просто поместите @@RenderBody(), который действует как флаг для средней части вашего контента. Извините за перевод VB.

Использует пример моего использования.

Using Html.UseTemplate("ContentWrapper")

    @Html.EditorFor(Function(m) m.Var1, "TemplateHint")
    @Html.EditorFor(Function(m) m.Var2, "TemplateHint")
    @Html.EditorFor(Function(m) m.Var3)

End Using

Мой Частичный выглядит так...

<div class="content"> 
    @@RenderBody()
</div>

Если вы используете Razor и MVC 3, очень легко написать быстрый вспомогательный метод, который будет находиться в папке app_code (я назову его MyHtmlHelpers)

Я бы попробовал что-то немного другое и немного проще, например:

@helper myTemplate(string title, string markup){
    <div class="module">
        <h3>@title</h3>
        @markup
    </div>
}

И способ, которым вы используете его из файла.cshtml, выглядит следующим образом:

@MyHtmlHelpers.myTemplate('title','markup')

Должно работать, если я вас правильно понимаю.

Другие вопросы по тегам