C# 使用EditorFor和LabelFor重构呈现不同属性的类似CHTML

C# 使用EditorFor和LabelFor重构呈现不同属性的类似CHTML,c#,asp.net-mvc,razor,C#,Asp.net Mvc,Razor,我正在构建一个项目,其中包含许多关于razor视图的通用代码 例如: <div class="form-group"> @Html.LabelFor(model => model.LayoutFrontAmount, htmlAttributes: new { @class = "control-label col-xs-12 col-sm-4 col-md-3" }) <div class="col-xs-4 col-sm-2 col-md-2 col-

我正在构建一个项目,其中包含许多关于razor视图的通用代码

例如:

<div class="form-group">
    @Html.LabelFor(model => model.LayoutFrontAmount, htmlAttributes: new { @class = "control-label col-xs-12 col-sm-4 col-md-3" })
    <div class="col-xs-4 col-sm-2 col-md-2 col-lg-1">
        @Html.EditorFor(model => model.LayoutFrontAmount, new { htmlAttributes = new { @class = "form-control" } })
    </div>
    <div class="col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3">
        <span class="help-block">@Html.ValidationMessageFor(model => model.LayoutFrontAmount, "", new { @class = "text-danger" })</span>
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.LayoutFrontBackAmount, htmlAttributes: new { @class = "control-label col-xs-12 col-sm-4 col-md-3" })
    <div class="col-xs-4 col-sm-2 col-md-2 col-lg-1">
        @Html.EditorFor(model => model.LayoutFrontBackAmount, new { htmlAttributes = new { @class = "form-control" } })
    </div>
    <div class="col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3">
        <span class="help-block">@Html.ValidationMessageFor(model => model.LayoutFrontBackAmount, "", new { @class = "text-danger" })</span>
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.LayoutTRC, htmlAttributes: new { @class = "control-label col-xs-12 col-sm-4 col-md-3" })
    <div class="col-xs-4 col-sm-2 col-md-2 col-lg-1">
        @Html.EditorFor(model => model.LayoutTRC, new { htmlAttributes = new { @class = "form-control" } })
    </div>
    <div class="col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3">
        <span class="help-block">@Html.ValidationMessageFor(model => model.LayoutTRC, "", new { @class = "text-danger" })</span>
    </div>
</div>

取决于LayoutFrontAmount、LayoutFrontBackAmount和LayoutRC的类型。这些都是线吗?如果是这样,您可以拥有一个公共视图文件,该文件存储用于显示每个模板的模板,然后在主视图中使用
@Html.Partial()
显示每个模板:

MyView.cshtml

@model string
<div class="form-group">
    @Html.LabelFor(model => Model, htmlAttributes: new { @class = "control-label col-xs-12 col-sm-4 col-md-3" })
    <div class="col-xs-4 col-sm-2 col-md-2 col-lg-1">
        @Html.EditorFor(model => Model, new { htmlAttributes = new { @class = "form-control" } })
    </div>
    <div class="col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3">
        <span class="help-block">@Html.ValidationMessageFor(model => Model, "", new { @class = "text-danger" })</span>
    </div>
</div>

如果它们是不同的类型,则会带来更大的挑战。

您可以创建一个HtmlHelper扩展方法,该方法将生成属性的所有html,包括label和input元素

using System;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace YourAssembly.Html
{
  public static class BootstrapHelper
  {
    public static MvcHtmlString BootstrapEditorFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
    {      
      MvcHtmlString label = LabelExtensions.LabelFor(helper, expression, new { @class = "control-label col-xs-12 col-sm-4 col-md-3" });
      MvcHtmlString editor = EditorExtensions.EditorFor(helper, expression, new { htmlAttributes = new { @class = "form-control" } });
      MvcHtmlString validation = ValidationExtensions.ValidationMessageFor(helper, expression, null, new { @class = "text-danger" });

      // Build the input elements
      TagBuilder editorDiv = new TagBuilder("div");
      editorDiv.AddCssClass("col-xs-4 col-sm-2 col-md-2 col-lg-1");
      editorDiv.InnerHtml = editor.ToString();
      // Build the validation message elements
      TagBuilder validationSpan = new TagBuilder("span");
      validationSpan.AddCssClass("help-block");
      validationSpan.InnerHtml = validation.ToString();
      TagBuilder validationDiv = new TagBuilder("div");
      validationDiv.AddCssClass("col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3");
      validationDiv.InnerHtml = validationSpan.ToString();
      // Combine all elements
      StringBuilder html = new StringBuilder();
      html.Append(label.ToString());
      html.Append(editorDiv.ToString());
      html.Append(validationDiv.ToString());
      // Build the outer div
      TagBuilder outerDiv = new TagBuilder("div");
      outerDiv.AddCssClass("form-group");
      outerDiv.InnerHtml = html.ToString();
      return MvcHtmlString.Create(outerDiv.ToString());
    }
  }
}
现在,在主视图中,您可以使用以下3行代码生成问题中显示的所有html

@Html.BootstrapEditorFor(m => m.LayoutFrontAmount)
@Html.BootstrapEditorFor(m => m.LayoutFrontBackAmount)
@Html.BootstrapEditorFor(m => m.LayoutTRC)

如果你想让它在多个项目中重用,可以在单独的dll中编译它,并在你的项目中添加对它的引用。

你可以创建一个HtmlHelper扩展方法,该方法生成标签、表单控件和验证消息(以及相关的
div
元素),你可以将其用作(比如)
@Html.MyEditorFor(model=>model.LayoutFrontAmount)
提供了一个示例谢谢@StephenMuecke,但我更喜欢一个最接近、更清晰的HTML结构,很难查看和理解whatSorry在哪里,不确定您的意思。创建扩展方法后,视图中只需要3行代码(
@HTML.MyEditorFor)(m=>m.someProperty)
)要生成所有html,就像@Chase的答案一样,我可以查看视图并查看html结构。谢谢。质询的意思是,如果我有不同的类型,我需要创建“MyViewInt”和“MyViewString”?如果它们属于不同的类型,则很难在一个模型视图下统一它们。如果只使用整数和字符串,则可以轻松地将整数转换为字符串并将其传递给同一个模型。但是,这些项的编辑器将基于视图顶部指定的模型类型。如果转换int转换为字符串并使用字符串编辑器,您必须在编辑后解析字符串中的整数。与@Stephen的答案相比,使用内置帮助器方法的性能如何?不确定对性能的影响,但在我看来,使用HtmlHelper扩展方法的灵活性和可维护性较差。HtmlHelper扩展将每次您想要更改视图的显示方式时,都必须重新编译(这在实践中经常发生)。如果您仅使用cshtml文件执行纯粹基于视图的路由,则无需重新编译任何源代码即可编辑这些文件。做得很好。旁注:虽然我相信这是实现OP要求的唯一方法(因为在Razor视图/帮助器中,您无法真正实现通用性)我会认真考虑在这个C版本上保持重复的HTML标记。史蒂芬非常感谢你的例子:当我今天醒来的时候,我突然想到,如果我需要通过jQuery与元素交互,我就没有机会做得对了?@AlexeiLevenkov嗨,你说的重复HTML标记是什么意思?@Patrick我的意思是我更喜欢你在问题中发布的HTML代码-虽然它有重复,但大多数人都可以浏览并理解。看在code Stephen提供的情况下,只有一小部分开发人员能够对结果输出进行推理或快速调整。在某些情况下,这是可以的(即相同的布局必须出现在大量位置),因此需要仔细权衡哪种方法对于特定的案例/开发团队更具可持续性。它仍然会创建与问题中的代码完全相同的html输出(并且您的输入具有
id
属性),这样您就可以与jQuery完全相同的方式进行交互。
using System;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace YourAssembly.Html
{
  public static class BootstrapHelper
  {
    public static MvcHtmlString BootstrapEditorFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
    {      
      MvcHtmlString label = LabelExtensions.LabelFor(helper, expression, new { @class = "control-label col-xs-12 col-sm-4 col-md-3" });
      MvcHtmlString editor = EditorExtensions.EditorFor(helper, expression, new { htmlAttributes = new { @class = "form-control" } });
      MvcHtmlString validation = ValidationExtensions.ValidationMessageFor(helper, expression, null, new { @class = "text-danger" });

      // Build the input elements
      TagBuilder editorDiv = new TagBuilder("div");
      editorDiv.AddCssClass("col-xs-4 col-sm-2 col-md-2 col-lg-1");
      editorDiv.InnerHtml = editor.ToString();
      // Build the validation message elements
      TagBuilder validationSpan = new TagBuilder("span");
      validationSpan.AddCssClass("help-block");
      validationSpan.InnerHtml = validation.ToString();
      TagBuilder validationDiv = new TagBuilder("div");
      validationDiv.AddCssClass("col-xs-12 col-md-8 col-sm-offset-4 col-md-offset-3");
      validationDiv.InnerHtml = validationSpan.ToString();
      // Combine all elements
      StringBuilder html = new StringBuilder();
      html.Append(label.ToString());
      html.Append(editorDiv.ToString());
      html.Append(validationDiv.ToString());
      // Build the outer div
      TagBuilder outerDiv = new TagBuilder("div");
      outerDiv.AddCssClass("form-group");
      outerDiv.InnerHtml = html.ToString();
      return MvcHtmlString.Create(outerDiv.ToString());
    }
  }
}
<namespaces>
  <add namespace="System.Web.Mvc" />
  ....
  <add namespace="yourAssembly.Html " /> // add this
</namespaces>
@Html.BootstrapEditorFor(m => m.LayoutFrontAmount)
@Html.BootstrapEditorFor(m => m.LayoutFrontBackAmount)
@Html.BootstrapEditorFor(m => m.LayoutTRC)