Создать метод расширения для создания открывающих и закрывающих тегов, таких как Html.BeginForm () - PullRequest
9 голосов
/ 13 марта 2010

Интересно, возможно ли создать метод расширения, который по функциональности и поведению будет аналогичен Html.BeginForm (), так как он будет генерировать полный тег Html, и я мог бы указать его содержимое в тегах <% { & } %>.

Например, у меня может быть вид как:

<% using(Html.BeginDiv("divId")) %>
<% { %>
    <!-- Form content goes here -->
<% } %>

Эта возможность была бы очень полезна в контексте функциональности, которую я пытаюсь создать на примере этого вопроса

Это дало бы мне возможность создавать контейнеры для типов, которыми я буду

<% var myType = new MyType(123, 234); %>
<% var tag = new TagBuilder("div"); %>

<% using(Html.BeginDiv<MyType>(myType, tag) %>
<% { %>
    <!-- controls used for the configuration of MyType  -->
    <!-- represented in the context of a HTML element, e.g.:  -->

    <div class="MyType" prop1="123" prop2="234">
        <!-- add a select here -->
        <!-- add a radio control here -->
        <!-- whatever, it represents elements in the context of their type -->
    </div>

<% } %>

Я понимаю, что это приведет к недопустимому XHTML, но я думаю, что могут быть и другие преимущества, которые перевешивают это, тем более что этот проект не требует, чтобы XHTML соответствовал стандартам W3C.

Спасибо

Dave

1 Ответ

14 голосов
/ 13 марта 2010

Не совсем уверен, какое значение это имеет по сравнению с простым определением элемента <div>, но что-то вроде этого

/// <summary>
/// Represents a HTML div in an Mvc View
/// </summary>
public class MvcDiv : IDisposable
{
    private bool _disposed;
    private readonly ViewContext _viewContext;
    private readonly TextWriter _writer;

    /// <summary>
    /// Initializes a new instance of the <see cref="MvcDiv"/> class.
    /// </summary>
    /// <param name="viewContext">The view context.</param>
    public MvcDiv(ViewContext viewContext) {
        if (viewContext == null) {
            throw new ArgumentNullException("viewContext");
        }
        _viewContext = viewContext;
        _writer = viewContext.Writer;
    }

    /// <summary>
    /// Performs application-defined tasks associated with 
    /// freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(true /* disposing */);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Releases unmanaged and - optionally - managed resources
    /// </summary>
    /// <param name="disposing"><c>true</c> to release both 
    /// managed and unmanaged resources; <c>false</c> 
    /// to release only unmanaged resources.</param>
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            _disposed = true;
            _writer.Write("</div>");
        }
    }

    /// <summary>
    /// Ends the div.
    /// </summary>
    public void EndDiv()
    {
        Dispose(true);
    }
}


/// <summary>
/// HtmlHelper Extension methods for building a div
/// </summary>
public static class DivExtensions
{
    /// <summary>
    /// Begins the div.
    /// </summary>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <returns></returns>
    public static MvcDiv BeginDiv(this HtmlHelper htmlHelper)
    {
        // generates <div> ... </div>>
        return DivHelper(htmlHelper, null);
    }

    /// <summary>
    /// Begins the div.
    /// </summary>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <param name="htmlAttributes">The HTML attributes.</param>
    /// <returns></returns>
    public static MvcDiv BeginDiv(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes)
    {
        // generates <div> ... </div>>
        return DivHelper(htmlHelper, htmlAttributes);
    }

    /// <summary>
    /// Ends the div.
    /// </summary>
    /// <param name="htmlHelper">The HTML helper.</param>
    public static void EndDiv(this HtmlHelper htmlHelper)
    {
        htmlHelper.ViewContext.Writer.Write("</div>");
    }

    /// <summary>
    /// Helps build a html div element
    /// </summary>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <param name="htmlAttributes">The HTML attributes.</param>
    /// <returns></returns>
    private static MvcDiv DivHelper(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes)
    {
        TagBuilder tagBuilder = new TagBuilder("div");
        tagBuilder.MergeAttributes(htmlAttributes);

        htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
        MvcDiv div = new MvcDiv(htmlHelper.ViewContext);

        return div;
    }
}

и пользуйся вот так

<% using (Html.BeginDiv(new Dictionary<string, object>{{"class","stripey"}}))
{ %>
       <p>Content Here</p>
<% } %>

будет отображать

<div class="stripey">
    <p>Content Here</p>
</div>

или без атрибутов html

<% using (Html.BeginDiv())
{ %>
       <p>Content Here</p>
<% } %>
...