ViewModel中的StringLength未在文本框上设置maxlength

时间:2013-02-06 22:04:06

标签: razor asp.net-mvc-4

这是我的ViewModel中的属性:

[Display(Name = "Ext.")]
[MaxLength(6, ErrorMessage = "Must be a maximum of 6 characters")]
[StringLength(6)]
public string Extension { get; set; }

在我的观点中:

@Html.EditorFor(model => model.Extension)

它呈现:

<input class="text-box single-line" data-val="true" data-val-length="The field Ext. must be a string with a maximum length of 6." data-val-length-max="6" id="Extension" name="Extension" type="text" value="" />

这应该在我的文本框中设置maxlength属性吗?如果没有,我怎么能用DataAttributes做到这一点?

3 个答案:

答案 0 :(得分:4)

  

我想在ViewModel中设置的属性来控制它   可能的。

ASP.NET MVC提供了一个可扩展的系统来完成这个任务。以下是您需要做的事情:

  1. 实施自定义ModelMetadataProvider
  2. 查找StringLengthAttributeMaxLengthAttribute,提取信息并将其添加到ModelMetadata
  3. 提供使用该信息的自定义编辑器模板。
  4. 第1步:实施自定义ModelMetadataProvider

    创建一个派生自ModelMetadataProvider的类。通常,您将从DataAnnotationsModelMetadataProvider派生,因为这提供了一些默认功能,这意味着您只需要覆盖名为CreateMetadata的单个方法。

    第2步:提取信息:

    要获取信息,您需要查找属性,提取最大长度信息并将其添加到AdditionalValues的{​​{1}}字典中。实现看起来像这样(这是整个实现):

    ModelMetadata

    为了让ASP.NET MVC使用它,您需要在public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata( IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { // Call the base class implementation to create the default metadata... var metadata = base.CreateMetadata( attributes, containerType, modelAccessor, modelType, propertyName); // Extract the stringLengthAttribute (you can do the same for the // MaxLengthAttribute if you want). var attr = attributes .OfType<StringLengthAttribute>() .First(); // This could be getting called on a property that doesn't have the // attribute so make sure you check for null! if (attr != null) { metadata.AdditionalValues["maxLength"] = attr.MaximumLength; } return metadata; } } 中的Application_Start方法中注册它。

    Global.asax

    第3步:创建自定义编辑器模板。

    您现在需要创建一个使用该信息的视图。在ModelMetadataProviders.Current = new CustomModelMetadataProvider(); 文件夹中创建名为String的新视图。

    <强> String.cshtml

    Views\Shared\

    运行应用程序时,您将通过调用@{ object maxLength; if (!ViewData.ModelMetadata.AdditionalValues .TryGetValue("maxLength", out maxLength)) { maxLength = 0; } var attributes = new RouteValueDictionary { {"class", "text-box single-line"}, { "maxlength", (int)maxLength }, }; } @Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes) 获得以下HTML输出。

    @Html.EditorFor

    如果您想了解更多有关模型元数据提供程序系统的信息,Brad Wilson has a series of blog posts详细说明它是如何工作的(这些是在Razor视图引擎之前编写的,因此某些视图语法有点时髦但其他方面的信息是健全的。)

答案 1 :(得分:4)

基本上基于Brad的答案,使用lambda语法包含在Html助手的扩展名中,这样你就不会用反射内容污染你的Razor视图:

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;

public static class HtmlHelper
{
    public static int? MaxLength<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression)
    {
        MemberExpression memberExpression = (MemberExpression)expression.Body;

        PropertyInfo property = typeof(TModel)
            .GetProperty(memberExpression.Member.Name);

        StringLengthAttribute attribute = (StringLengthAttribute)property
            .GetCustomAttributes(typeof(StringLengthAttribute), true)
            .FirstOrDefault();

        if (attribute != null)
        {
            return attribute.MaximumLength;
        }

        return null;
    }
}

像这样使用它:

@Html.TextBoxFor(x => x.Name, new { maxlength = Html.MaxLength(x => x.Name) })

其中x指的是您的模型。

如果未为该属性声明StringLengthAttribute,则会返回null,并且maxlength属性在文本框元素上将为空。

请记住在剃须刀页面中使用,以便您可以访问该方法。

@using HtmlHelper

您还需要使用none null-able结果来克服编译错误。

答案 2 :(得分:2)

我碰到了类似的东西,这是我快速而又肮脏的解决方案:

在.cshtml文件的顶部添加以下行:

@{
var max = ((System.ComponentModel.DataAnnotations.StringLengthAttribute)(typeof(MyType))
.GetProperty("MyProp")
.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), true)[0]).MaximumLength;    
}

下面的html替换了EditorFor:

@Html.TextBoxFor(model => model.Extension, htmlAttributes: new {maxlength=max })

我最终决定我只是在剧本中这样做:

<script>
    $(function ()
    {
        var max = $("#myinput").attr("data-val-length-max");
        $("#myinput").attr("maxlength", max);
    });
</script>

但如果您不想添加脚本,则第一个示例应该有效。