Рефакторинг формы в MVC2 - PullRequest
       38

Рефакторинг формы в MVC2

2 голосов
/ 07 сентября 2010

Я снова и снова вставляю этот код во многие представления, связанные с формами.Существует ли простой подход к рефакторингу следующей разметки из представления в MVC2?Единственной изменяющейся частью является маршрут для ссылки отмены (LocalizedSaveButton и LocalizedCancelLink являются вспомогательными методами, которые я создал).Я попытался извлечь его в PartialView, но я потерял функциональность BeginForm.Есть предложения?

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div class="span-14">
    <% Html.EnableClientValidation(); %>
    <%using (Html.BeginForm())
      {%>
    <fieldset>
        <legend>Edit Profile</legend>
        <%=Html.AntiForgeryToken() %>
        <%=Html.EditorForModel() %>
        <div class="span-6 prepend-3">
            <%=Html.LocalizedSaveButton() %>
            <%=Html.LocalizedCancelLink(RoutingHelper.HomeDefault()) %>                
        </div>
    </fieldset>
    <%}%>
</div>

Ответы [ 2 ]

1 голос
/ 07 сентября 2010

Вот что я придумал: В основном это работает, но я не смог заставить Html.EnableClientValidation () взаимодействовать с визуализированной формой.

namespace System.Web.Mvc
{
        public class MyForm : IDisposable
        {
            private bool _disposed;
            private readonly HttpResponseBase _httpResponse;

        public MyForm(HttpResponseBase httpResponse)
        {
            if (httpResponse == null)
            {
                throw new ArgumentNullException("httpResponse");
            }
            _httpResponse = httpResponse;
        }

        public void Dispose()
        {
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;
                _httpResponse.Write("</form>");
            }
        }

        public void EndForm()
        {
            Dispose(true);
        }
    }
}

public static class MyFormExtensions
{
    public static MyForm FormHelper(
        this HtmlHelper htmlHelper, 
        string formAction, 
        FormMethod method, 
        IDictionary<string, object> htmlAttributes, 
        string formLegendTitle)
    {
        TagBuilder tagBuilder = new TagBuilder("form");

        tagBuilder.MergeAttributes(htmlAttributes);

        tagBuilder.MergeAttribute("action", formAction);
        tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
        HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
        httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));

        return new MyForm(httpResponse);
    }



    public static MyForm MyBeginForm(this HtmlHelper html, string formLegendTitle) {

        string formAction = html.ViewContext.HttpContext.Request.RawUrl;
        var result = FormHelper(html,formAction, FormMethod.Post, null, formLegendTitle );

            html.ViewContext.Writer.Write("<fieldset>");
            html.ViewContext.Writer.Write(String.Format("<legend>{0}</legend>", formLegendTitle));
            html.ViewContext.Writer.Write("<div class=\"span-14\">");
            html.ViewContext.Writer.Write(html.AntiForgeryToken());
            html.ViewContext.Writer.Write(html.EditorForModel());
            html.ViewContext.Writer.Write("<div class=\"span-6 prepend-3 buttons\">");
            html.ViewContext.Writer.Write(html.LocalizedSaveButton());
            html.ViewContext.Writer.Write("</div>");
            html.ViewContext.Writer.Write("</div>");
            html.ViewContext.Writer.Write("</fieldset>");

        return result;

    }

    public static void EndForm(this HtmlHelper htmlHelper)
    {
        HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
        httpResponse.Write("</form>");
    }
}
1 голос
/ 07 сентября 2010

Вы можете обернуть свой код в Html-расширение, такое как BeginForm.Из вашего кода вызовите BeginForm в нужном месте.

Вы должны вернуть объект, который реализует IDisposable.В методе dispose вы вызываете Dispose для сохраненного результата в BeginForm.

В результате вы получаете:

<% using (Html.MyBeginForm()) { %>
    <%=Html.LocalizedSaveButton() %> 
    <%=Html.LocalizedCancelLink(RoutingHelper.HomeDefault()) %>   
<% } %>

Хитрость заключается не в том, чтобы вернуть строку или MvcHtmlString, а непосредственно записать выводиспользуя:

htmlHelper.ViewContext.Writer.Write(....);

Это будет делать что-то вроде:

public class MyForm : IDisposable {
    private MvcForm _form;
    private ViewContext _ctx; 

    public MyForm(HtmlHelper html, /* other params */) {
       _form = html.BeginForm();
       _ctx = html.ViewContext;
    }

    public Dispose() {
        _form.Dispose();
        _ctx.Writer.Write("html part 3 => closing tags");
    }
}

и расширение:

public static MyForm MyBeginForm(this HtmlHelper html /* other params */) {
    html.ViewContext.Writer.Write("html part 1");
    var result = new MyForm(html);
    html.ViewContext.Writer.Write("html part 2");
    return result;
}

Отказ от ответственности : Это не проверенокод.

...