Base type Razor / Templated Razor Delegates with the keyword "using"

I currently have a div container for all input fields in my form, similar to:

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

I would like to know how I could encapsulate this using a template razor delegate (or any other trick ), just like we use:

 @using (Html.BeginForm()) { } 

I could just wrap my elements, for example:

 @using (Html.ContentField()) { @Html.LabelFor(m => m.Name) @Html.TextBoxFor(m => m.Name) } 
+6
source share
3 answers

Using the Razor viewer, this is what works:

 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); } } } 

FYI: using the old ASPX mechanism, here's how to do it .

+7
source

The accepted answer was very helpful. I changed and updated it a little for my project, and I feel that this version will be a little more understandable for people who just want to jump in and achieve a result.

Changes include:

  • Updated to use anonymous types instead of IDictionary, as it is now standard.
  • The Begin / End ... syntax has been removed, since I will only use it with the using () syntax, and for this I feel this is more understandable.
  • Careful designation for clarity.
  • Added headerText argument, which my panel uses to create a separate div header. It is easy to remove if you do not need / need it.
  • Several methods have been implemented.
  • If you are looking for a panel assistant for KendoUI - well, this is exactly what happens. I have a class called a panel that references, and that just adds marker and width to the KendoUI tags.

    using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Web.Mvc;

    namespace MyProject.Web.HtmlHelpers.Extensions {public static class LayoutExtensions {public static StyledPanel Panel (this HtmlHelper htmlHelper, htmlAttributes = null, string headerText = null) {return GetStyledPanel (htmlHelper, headerTextutes, html; }

      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); } } 

    }

Use may be as follows:

 @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> } 

Or simply:

 @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> } 
+2
source

Let's see (or guess) what Html.BeginForm() does. In terms of "rendering," it usually just returns the start tag of the form to the html output. it is available because in this case it knows when the internal html content for the form has finished rendering, and it can display the end </form> in its Dispose() method. With all this, you get - firstly, open the form tag than the custom html content you want, and after that comes the final tag. Result - you get the full html form in the output.

 <form> ...contents(Result of Html.TextBoxFor, etc. helpers) </form> 

I think your situation will be best resolved in case of form. At the moment, I don’t have much time to write the full code, but if you look at FormExtensions.BeginForm , looking at the source code reflector (Thanks @druttka) (if you have an old version or a purchased license) or http: // wiki .sharpdevelop.net / ilspy.ashx and the explanations above, you can get a great point where from the beginning. Remove unnecessary code from the BeginForm method, create your MvcContentField: IDisposable class instead of MvcForm, change Dispose() on it to display the end tag of the div, and you will get exactly what you need.

+1
source

Source: https://habr.com/ru/post/885814/


All Articles