问题描述
|
我目前在表单中的所有输入字段中都有一个“ 0”容器,类似于:
<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)
}
解决方法
使用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引擎,这里是操作方法。
,接受的答案非常有帮助。我为我的项目做了一些更改和更新,我觉得对于只想参与进来并完成工作的人来说,此版本会更清晰一些。
更改包括:
升级为使用匿名类型而不是IDictionary,因为现在这已成为标准。
删除了Begin / End ...语法,因为我将只将它与using()语法一起使用,因此我觉得这更加清楚。
为清楚起见,对命名进行了调整。
添加了headerText参数,我的面板用来创建单独的div标头。如果您不需要/不需要,可以轻松删除它。
重构出几种方法。
如果您恰巧在寻找KendoUI的面板帮助程序-恰好就是这样。我有一个称为panel的类,它引用了该类,并且仅向KendoUI标签添加了边距和宽度。
使用系统;
使用System.Diagnostics.CodeAnalysis;
使用System.IO;
使用System.Web.Mvc;
命名空间MyProject.Web.HtmlHelpers.Extensions
{
公共静态类LayoutExtensions
{
公共静态StyledPanel面板(此HtmlHelper htmlHelper,对象htmlAttributes = null,字符串headerText = null)
{
返回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>
}
,让我们看一看(或猜测)Html.BeginForm()
的作用。从“渲染角度”来看,它通常只是将开始表单标记渲染到html输出中。它是一次性的,因为在这种情况下,它知道表单的内部html内容何时完成渲染,并且可以使用in10ѭ方法渲染end9ѭ标记。有了这些,您就可以得到-首先,呈现打开的form
标签,然后显示您想要的自定义html内容,然后是end标签。结果-您在输出中获得完整的html表单。
<form>
...contents(Result of Html.TextBoxFor,etc. helpers)
</form>
我认为您的情况最好以表格形式解决。目前我没有太多时间来编写完整的代码,但是如果您通过查看源代码(感谢@druttka)反射器来查看old13ѭ(如果您有旧版本或购买了许可证)或http://wiki.sharpdevelop.net/ilspy.ashx和上述说明,您可以从头开始。从BeginForm方法中删除不必要的代码,创建MvcContentField:IDisposable类而不是MvcForm,将其上的ѭ10更改为呈现end div标签,您将完全得到所需的内容。