I currently have a div
container for all of the 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 could I encapsulate this using a templated razor delegate (or any other trick), so just like we use:
@using (Html.BeginForm()) {
}
I could simply wrap my elements like:
@using (Html.ContentField()) {
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
}
Using the Razor View Engine, here 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 engine, here's how to do it.
The accepted answer was very helpful. I changed and updated it a bit for my project, and I feel that this version will be slightly more clear for people who just want to jump in and get things done.
Changes include:
If you happen to be looking for a panel helper for KendoUI -- well, that happens to be what this is. I have a class called panel that this references, and that just adds margin 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, object htmlAttributes = null, string 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);
}
}
}
Usage could be like this:
@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 just:
@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>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With