Базовый тип Razor / Templated Razor Delegates с ключевым словом «using» - PullRequest
6 голосов
/ 13 апреля 2011

В настоящее время у меня есть контейнер div для всех полей ввода в моей форме, похожий на:

<div class="ux-single-field ui-widget-content ui-corner-all">
  @Html.LabelFor(m => m.Name)
  @Html.TextBoxFor(m => m.Name)
</div>

Я хотел бы знать, как я могу инкапсулировать это, используя шаблонную бритву делегировать (или любой другой трюк ), так же, как мы используем:

@using (Html.BeginForm()) {
}

Я мог бы просто обернуть свои элементы как:

@using (Html.ContentField()) {
  @Html.LabelFor(m => m.Name)
  @Html.TextBoxFor(m => m.Name)
}

Ответы [ 3 ]

7 голосов
/ 13 апреля 2011

Используя Razor View Engine, вот что работает:

namespace MyProject.Web.Helpers.Extensions
{
    public static class LayoutExtensions
    {
        public static ContentField BeginContentField(this HtmlHelper htmlHelper)
        {
            return FormHelper(htmlHelper, new RouteValueDictionary());
        }

        public static ContentField BeginContentField(this HtmlHelper htmlHelper, RouteValueDictionary htmlAttributes)
        {
            return FormHelper(htmlHelper, htmlAttributes);
        }

        public static void EndContentField(this HtmlHelper htmlHelper)
        {
            htmlHelper.ViewContext.Writer.Write("</div>");
        }

        private static ContentField FormHelper(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes)
        {
            TagBuilder tagBuilder = new TagBuilder("div");
            tagBuilder.MergeAttributes(htmlAttributes);
            tagBuilder.MergeAttribute("class", "ux-single-field ui-widget-content ui-corner-all");

            htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
            return new ContentField(htmlHelper.ViewContext.Writer);
        }
    }

    public class ContentField : IDisposable
    {
        private bool _disposed;
        private readonly TextWriter _writer;

        public ContentField(TextWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            _writer = writer;
        }

        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public void Dispose()
        {
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;

                _writer.Write("</div>");
            }
        }

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

К вашему сведению: Используя старый механизм ASPX, вот как это сделать .

2 голосов
/ 04 февраля 2013

Принятый ответ был очень полезным. Я немного изменил и обновил его для своего проекта, и я чувствую, что эта версия будет немного более понятной для людей, которые просто хотят подключиться и добиться цели.

Изменения включают в себя:

  • Обновлен для использования анонимных типов вместо IDictionary, так как теперь это кажется стандартом.
  • Удален синтаксис Begin / End ..., так как я буду когда-либо использовать его только с синтаксисом using (), и для этой цели я чувствую, что это более понятно.
  • Подправлены названия для ясности.
  • Добавлен аргумент headerText, который моя панель использует для создания отдельного заголовка div. Это легко удалить, если вам это не нужно / не нужно.
  • Рефакторинг нескольких методов.
  • Если вы ищете помощника по работе с панелью для KendoUI - ну, это как раз то, что нужно. У меня есть класс с именем panel, на который он ссылается, и он просто добавляет поля и ширину в теги KendoUI.

    с использованием Системы; использование System.Diagnostics.CodeAnalysis; используя System.IO; использование System.Web.Mvc;

    namespace MyProject.Web.HtmlHelpers.Extensions { открытый статический класс LayoutExtensions { общедоступная статическая панель StyledPanel (это HtmlHelper htmlHelper, объект htmlAttributes = null, строка headerText = null) { return GetStyledPanel (htmlHelper, headerText, htmlAttributes); } * * Тысяча двадцать-один

        private static StyledPanel GetStyledPanel(this HtmlHelper htmlHelper, string headerText, object htmlAttributes)
        {
    
            if (!string.IsNullOrWhiteSpace(headerText))
                RenderHeading(htmlHelper, headerText);
    
            RenderDiv(htmlHelper, htmlAttributes);
    
            return new StyledPanel(htmlHelper.ViewContext.Writer);
        }
    
        private static void RenderHeading(HtmlHelper htmlHelper, string headerText)
        {
            TagBuilder tagBuilder = new TagBuilder("div");
            tagBuilder.Attributes.Add("class", "panelHead");
            tagBuilder.SetInnerText(headerText);
    
            htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.Normal));
        }
    
        private static void RenderDiv(HtmlHelper htmlHelper, object htmlAttributes) 
        {
            TagBuilder Tag = new TagBuilder("div");
            Tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            Tag.MergeAttribute("class", "panel k-block k-shadow");
    
            htmlHelper.ViewContext.Writer.Write(Tag.ToString(TagRenderMode.StartTag));        
        }
    
    }
    
    public class StyledPanel : IDisposable
    {
        private bool m_Disposed;
        private readonly TextWriter m_Writer;
    
        public StyledPanel(TextWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("Writer was null. This should never happen.");
    
            m_Writer = writer;
        }
    
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (!m_Disposed)
            {
                m_Disposed = true;
                m_Writer.Write("</div>");
            }
        }
    
        public void EndForm()
        {
            Dispose(true);
        }
    }
    

    }

Использование может быть таким:

@using (Html.Panel(headerText: "My Header", 
                   htmlAttributes: new { style = "width: 800px;" }))
{ 
    <table>
            <tr>
                <td class="label">First Name:</td>
                <td class="content"><input name="thing" class="k-textbox" /></td>

                <td class="label">Last Name:</td>
                <td class="content"><input name="thing" class="k-textbox" /></td>
            </tr>
    </table>
}

или просто:

@using (Html.Panel())
{ 
    <table>
            <tr>
                <td class="label">First Name:</td>
                <td class="content"><input name="thing" class="k-textbox" /></td>

                <td class="label">Last Name:</td>
                <td class="content"><input name="thing" class="k-textbox" /></td>
            </tr>
    </table>
}
1 голос
/ 13 апреля 2011

Давайте посмотрим (или предположим), что делает Html.BeginForm().С «точки зрения рендеринга» он обычно просто отображает начальный тег формы в вывод html.он одноразовый, потому что в этом случае он знает, когда внутренний html-контент для формы завершил рендеринг, и может отображать конечный тег </form> в своем методе Dispose().Со всем этим вы получаете - сначала отображается открытый тег form, а затем настраиваемый HTML-контент, который вы хотите, и после этого идет конечный тег.Результат - вы получите полную HTML-форму в выводе.

<form>

...contents(Result of Html.TextBoxFor, etc. helpers)

</form>

Я думаю, что ваша ситуация будет лучше всего решена, как в случае формы.На данный момент у меня не так много времени, чтобы написать полный код, но если вы посмотрите на FormExtensions.BeginForm через просмотр рефлектора исходного кода (спасибо @druttka) (если у вас старая версия или купленная лицензия)или http://wiki.sharpdevelop.net/ilspy.ashx и пояснения, приведенные выше, вы можете понять, с чего начать.Удалите ненужный код из метода BeginForm, создайте свой класс MvcContentField: IDisposable вместо MvcForm, измените Dispose() на нем, чтобы отобразить тег end div, и вы получите именно то, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...