【问题标题】:Extending HTML Helper扩展 HTML 助手
【发布时间】:2014-01-08 22:03:58
【问题描述】:

我希望生成的代码类似于:

<div class="form-group">
    <label for="email">Email address</label>
    <input type="email" class="form-control" id="email" placeholder="Enter email">
</div>

使用这样的东西:

@Html.LabelledTextBoxFor(model => model.EmailAddress)

标签文本从 model.EmailAddress 派生的位置

这将使用数据注释来完成,例如

[Displayname("Email Address]

最好的方法是什么?

这会影响使用 jquery val 自动生成的客户端 JS 验证吗?

【问题讨论】:

  • 你想用javascript操作标签吗?
  • 不,我想扩展 C# Html 助手
  • 已经有这个msdn.microsoft.com/tr-tr/library/…的显示属性
  • 我知道这一点,但问题表明我希望能够使用 HTML 帮助程序创建上述 HTML,例如只用剃须刀页面 @Html.LabelledTextBoxFor(model => model .EmailAddress) 然后进入模型类,为名称提取数据注释,根据模型属性名称创建 id。
  • 我明白了,我会给你一个样本

标签: c# html asp.net-mvc twitter-bootstrap razor


【解决方案1】:

我写了一个扩展方法,也许这会有所帮助:

public static MvcHtmlString LabelledTextBoxFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
{
    ExpressionType type = expression.Body.NodeType;
    if (type == ExpressionType.MemberAccess)
    {
       MemberExpression memberExpression = (MemberExpression) expression.Body;
       var propName = memberExpression.Member.Name;

       var member = memberExpression.Member as PropertyInfo;

       var attributes = member.GetCustomAttributes();

       StringBuilder sb = new StringBuilder();
       foreach (var attribute in attributes)
       {
           if (attribute is DisplayAttribute)
           {
               DisplayAttribute d = attribute as DisplayAttribute;
               var displayName = d.Name;
               sb.Append("<div class=\"form-group\">");
               sb.AppendFormat("<label for=\"{0}\">{1}</label>", propName, displayName);
               sb.AppendFormat(
                        "<input type=\"email\" class=\"form-control\" id=\"{0}\" placeholder=\"Enter email\">",
                        propName);
               sb.Append("</div>");
               return MvcHtmlString.Create(sb.ToString());
             }
         }

     }
       return MvcHtmlString.Create("");
 }

您可以使用默认显示属性来指定显示名称。不需要自定义属性。您可以像这样使用此扩展:

@Html.LabelledTextBoxFor(model => model.EmailAddress)

注意:我自己试过了,它工作正常。

更新:更简单的版本

public static MvcHtmlString LabelledTextBoxFor2<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
    {
        ExpressionType type = expression.Body.NodeType;
        if (type == ExpressionType.MemberAccess)
        {
            var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            var displayName = metadata.DisplayName;
            var propName = metadata.PropertyName;

            StringBuilder sb = new StringBuilder();

            sb.Append("<div class=\"form-group\">");
            sb.AppendFormat("<label for=\"{0}\">{1}</label>", propName, displayName);
            sb.AppendFormat(
                        "<input type=\"email\" class=\"form-control\" id=\"{0}\" placeholder=\"Enter email\">",
                        propName);
             sb.Append("</div>");
             return MvcHtmlString.Create(sb.ToString());
        }

        return MvcHtmlString.Create("");
    }

【讨论】:

  • +1,但您可以简化:var metadata = ModelMetadata.FromLambdaExpression( expression, helper.ViewData );。这将为您提供一个包含显示名称等信息的抽象。
  • 对,我以前用过。反正我只是想确保这个属性有显示属性。我已经用简化版本更新了我的答案
【解决方案2】:

我会使用@Html.EditorFor 模板。因此,在您的 MVC 项目的 Views/Shared 中创建 EditorTemplates 文件夹,名称为 EmailAddress.cshtml - 它会为模型中定义的每个 [DataType(DataType.EmailAddress)] 显示此模板。 p>

所以:EmailAddress.cshtml 应该看起来像这样:

<div class="form-group">
<label for="email">@Html.LabelFor(x => x)</label>
@Html.TextBoxFor(x => x, new { @class = "form-control", placeholder = ViewData.ModelMetadata.Watermark })
</div>

模型应如下所示:

public class SomeModel {

    [DataType(DataType.EmailAddress)]
    [Display(Name="Some string for LabelFor", Prompt = "Placeholder in input"]
    public string SomeEmail { get; set; }
}

请注意,我使用了 Display metadata 的 Prompt 属性,我通过 EmailAddress.cshtml 中的 ViewData.ModelMetadata.Watermark 链接到占位符。 Html.LabelFor 将始终从 Display 中获取属性 Name,并且需要 DataType 用于 EditorTemplates 和模型属性之间的链接。

并通过使用来调用所有这些“魔法”

@Html.EditorFor(m=>m.SomeEmail)

在您使用SomeMode 模型的页面上。

我希望这确实有意义。

【讨论】:

    【解决方案3】:

    无需重新发明轮子。查看TwitterBootstrapMVC

    您要编写的代码类似于以下内容:

    @Html.Bootstrap().FormGroup().TextBoxFor(model => model.EmailAddress).Placeholder("Enter email")
    

    免责声明: 我是 TwitterBootstrapMVC 的作者。

    用于 Bootstrap 3 的 TwitterBootstrapMVC 不是免费的。请参阅网站上的详细信息。

    【讨论】:

    • 问题是,由于项目的性质,它必须是免费的
    【解决方案4】:

    数据注释进入属性上方的视图模型中:

    [DisplayName("Email Address")]
    public string EmailAddress { get; set; }
    

    那么,在你看来,你会有这样的东西:

    @Html.LabelFor(m => m.EmailAddress)
    @Html.TextBoxFor(m => m.EmailAddress, new { @placeholder="Enter email", @class="form-control", @id="email" })
    

    【讨论】:

    • 据我所知,如上所述,主要问题是不想同时为 @Html.LabelFor 和 TextBox 做。我想制作我自己的 HTML 助手,它结合了这两者并将它们包装在一个 DIV 中,以匹配问题中的给定代码。我知道现在听起来很傻,但是如果您考虑一下,一旦我开始工作,我将能够更轻松地集成 bootstrap 和 C#。
    • 啊,我相信已经有答案了。你看过这个吗? stackoverflow.com/questions/5824124/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多