扩展HTML Helper

时间:2014-01-08 22:03:59

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

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

<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验证吗?

4 个答案:

答案 0 :(得分:5)

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

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 :(得分:1)

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

所以: 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; }
}

请注意,我使用了显示元数据的提示属性,我通过ViewData.ModelMetadata.Watermark中的EmailAddress.cshtml链接到占位符。 Html.LabelFor将始终从显示中获取属性名称,并且在EditorTemplates和模型属性之间链接需要DataType。

使用

调用所有这些“魔法”
@Html.EditorFor(m=>m.SomeEmail)

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

我希望这确实有意义。

答案 2 :(得分:1)

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

您要撰写的代码与以下内容类似:

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

声明: 我是TwitterBootstrapMVC的自拍。

用于Bootstrap 3的TwitterBootstrapMVC不是免费的。详情请见网站。

答案 3 :(得分:0)

数据注释位于属性上方的viewmodel中:

[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" })