asp.net-mvc Asp.Net MVC 中 DataAnnotations StringLength 文本框的 maxlength 属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2386365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
maxlength attribute of a text box from the DataAnnotations StringLength in Asp.Net MVC
提问by Pervez Choudhury
I am working on an MVC2 application and want to set the maxlength attributes of the text inputs.
我正在开发一个 MVC2 应用程序,并希望设置文本输入的 maxlength 属性。
I have already defined the stringlength attribute on the Model object using data annotations and it is validating the length of entered strings correctly.
我已经使用数据注释在 Model 对象上定义了 stringlength 属性,它正在正确验证输入字符串的长度。
I do not want to repeat the same setting in my views by setting the max length attribute manually when the model already has the information. Is there any way to do this?
当模型已经有信息时,我不想通过手动设置最大长度属性在我的视图中重复相同的设置。有没有办法做到这一点?
Code snippets below:
代码片段如下:
From the Model:
从模型:
[Required, StringLength(50)]
public string Address1 { get; set; }
From the View:
从视图:
<%= Html.LabelFor(model => model.Address1) %>
<%= Html.TextBoxFor(model => model.Address1, new { @class = "text long" })%>
<%= Html.ValidationMessageFor(model => model.Address1) %>
What I want to avoid doing is:
我想避免做的是:
<%= Html.TextBoxFor(model => model.Address1, new { @class = "text long", maxlength="50" })%>
I want to get this output:
我想得到这个输出:
<input type="text" name="Address1" maxlength="50" class="text long"/>
Is there any way to do this?
有没有办法做到这一点?
采纳答案by Darin Dimitrov
I am not aware of any way to achieve this without resorting to reflection. You could write a helper method:
我不知道有什么方法可以在不诉诸反思的情况下实现这一目标。你可以写一个辅助方法:
public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var member = expression.Body as MemberExpression;
var stringLength = member.Member
.GetCustomAttributes(typeof(StringLengthAttribute), false)
.FirstOrDefault() as StringLengthAttribute;
var attributes = (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes);
if (stringLength != null)
{
attributes.Add("maxlength", stringLength.MaximumLength);
}
return htmlHelper.TextBoxFor(expression, attributes);
}
which you could use like this:
你可以这样使用:
<%= Html.CustomTextBoxFor(model => model.Address1, new { @class = "text long" })%>
回答by jrummell
If you're using unobtrusive validation, you can handle this client side as well:
如果您使用的是不显眼的验证,您也可以处理这个客户端:
$(document).ready(function ()
{
$("input[data-val-length-max]").each(function ()
{
var $this = $(this);
var data = $this.data();
$this.attr("maxlength", data.valLengthMax);
});
});
回答by Randhir
I use the CustomModelMetaDataProvider to achieve this
我使用 CustomModelMetaDataProvider 来实现这一点
Step 1. Add New CustomModelMetadataProvider class
步骤 1. 添加新的 CustomModelMetadataProvider 类
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
ModelMetadata metadata = base.CreateMetadata(attributes,
containerType,
modelAccessor,
modelType,
propertyName);
//Add MaximumLength to metadata.AdditionalValues collection
var stringLengthAttribute = attributes.OfType<StringLengthAttribute>().FirstOrDefault();
if (stringLengthAttribute != null)
metadata.AdditionalValues.Add("MaxLength", stringLengthAttribute.MaximumLength);
return metadata;
}
}
Step 2. In Global.asax Register the CustomModelMetadataProvider
步骤 2. 在 Global.asax 中注册 CustomModelMetadataProvider
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new CustomModelMetadataProvider();
}
Step 3. In Views/Shared/EditorTemplates Add a partial view called String.ascx
步骤 3. 在 Views/Shared/EditorTemplates 添加一个名为 String.ascx 的局部视图
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%if (!ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) { %>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line" }) %>
<% } else {
int maxLength = (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"];
%>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", MaxLength = maxLength })%>
<% } %>
Done...
完毕...
Edit. The Step 3 can start to get ugly if you want to add more stuff to the textbox. If this is your case you can do the following:
编辑。如果您想向文本框添加更多内容,则第 3 步可能会开始变得难看。如果是这种情况,您可以执行以下操作:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
IDictionary<string, object> Attributes = new Dictionary<string, object>();
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) {
Attributes.Add("MaxLength", (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"]);
}
if (ViewData.ContainsKey("style")) {
Attributes.Add("style", (string)ViewData["style"]);
}
if (ViewData.ContainsKey("title")) {
Attributes.Add("title", (string)ViewData["title"]);
}
%>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, Attributes)%>
回答by dcompiled
If you want this to work with a metadata class you need to use the following code. I know its not pretty but it gets the job done and prevents you from having to write your maxlength properties in both the Entity class and the View:
如果您希望它与元数据类一起使用,则需要使用以下代码。我知道它不漂亮,但它完成了工作并防止您必须在实体类和视图中编写 maxlength 属性:
public static MvcHtmlString TextBoxFor2<TModel, TProperty>
(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes = null
)
{
var member = expression.Body as MemberExpression;
MetadataTypeAttribute metadataTypeAttr = member.Member.ReflectedType
.GetCustomAttributes(typeof(MetadataTypeAttribute), false)
.FirstOrDefault() as MetadataTypeAttribute;
IDictionary<string, object> htmlAttr = null;
if(metadataTypeAttr != null)
{
var stringLength = metadataTypeAttr.MetadataClassType
.GetProperty(member.Member.Name)
.GetCustomAttributes(typeof(StringLengthAttribute), false)
.FirstOrDefault() as StringLengthAttribute;
if (stringLength != null)
{
htmlAttr = new RouteValueDictionary(htmlAttributes);
htmlAttr.Add("maxlength", stringLength.MaximumLength);
}
}
return htmlHelper.TextBoxFor(expression, htmlAttr);
}
Example class:
示例类:
[MetadataType(typeof(Person.Metadata))]
public partial class Person
{
public sealed class Metadata
{
[DisplayName("First Name")]
[StringLength(30, ErrorMessage = "Field [First Name] cannot exceed 30 characters")]
[Required(ErrorMessage = "Field [First Name] is required")]
public object FirstName { get; set; }
/* ... */
}
}
回答by bkwdesign
While I'm personally loving jrummel's jquery fix, here's another approach to keeping a single-source-of-truth up in your model...
虽然我个人喜欢 jrummel 的 jquery 修复,但这是另一种在模型中保持单一事实来源的方法......
Not pretty, but.. has worked o.k. for me...
不漂亮,但是……对我来说还可以……
Instead of using property decorations, I just define some well-named public constants up in my model library/dll, and then reference them in my view via the HtmlAttributes, e.g.
我没有使用属性修饰,而是在我的模型库/dll 中定义了一些命名良好的公共常量,然后通过 HtmlAttributes 在我的视图中引用它们,例如
Public Class MyModel
Public Const MAX_ZIPCODE_LENGTH As Integer = 5
Public Property Address1 As String
Public Property Address2 As String
<MaxLength(MAX_ZIPCODE_LENGTH)>
Public Property ZipCode As String
Public Property FavoriteColor As System.Drawing.Color
End Class
Then, in the razor view file, in the EditorFor... use an HtmlAttirubte object in the overload, supply the desired max-length property and referenece the constant.. you'll have to supply the constant via a fully qualied namespace path... MyCompany.MyModel.MAX_ZIPCODE_LENGTH.. as it won't be hanging right off the model, but, it works.
然后,在 razor 视图文件中,在 EditorFor... 在重载中使用 HtmlAttirubte 对象,提供所需的 max-length 属性并引用常量..您必须通过完全限定的命名空间路径提供常量。 .. MyCompany.MyModel.MAX_ZIPCODE_LENGTH .. 因为它不会直接挂在模型上,但是,它可以工作。
回答by Dave Clemmer
I found Darin's reflection based approach to be especially helpful. I found that it was a little more reliable to use the metadata ContainerTypeas the basis to get the property info, as this method can get called within mvc editor/display templates (where TModelends up being a simple type such as string).
我发现 Darin 基于反射的方法特别有用。我发现使用元数据ContainerType作为获取属性信息的基础更可靠,因为可以在 mvc 编辑器/显示模板中调用此方法(TModel最终是一个简单的类型,例如string)。
public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var metadata = ModelMetadata.FromLambdaExpression( expression, new ViewDataDictionary<TModel>( htmlHelper.ViewDataContainer.ViewData ) );
var stringLength = metadata.ContainerType.GetProperty(metadata.PropertyName)
.GetCustomAttributes(typeof(StringLengthAttribute), false)
.FirstOrDefault() as StringLengthAttribute;
var attributes = (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes);
if (stringLength != null)
{
attributes.Add("maxlength", stringLength.MaximumLength);
}
return htmlHelper.TextBoxFor(expression, attributes);
}
回答by Carter Medlin
Here are some static methods you can use to get the StringLength, or any other attribute.
以下是一些可用于获取 StringLength 或任何其他属性的静态方法。
using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
public static class AttributeHelpers {
public static Int32 GetStringLength<T>(Expression<Func<T,string>> propertyExpression) {
return GetPropertyAttributeValue<T,string,StringLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}
//Optional Extension method
public static Int32 GetStringLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
return GetStringLength<T>(propertyExpression);
}
//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
var expression = (MemberExpression)propertyExpression.Body;
var propertyInfo = (PropertyInfo)expression.Member;
var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;
if (attr==null) {
throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
}
return valueSelector(attr);
}
}
Using the static method...
使用静态方法...
var length = AttributeHelpers.GetStringLength<User>(x => x.Address1);
Or using the optional extension method on an instance...
或者在实例上使用可选的扩展方法......
var player = new User();
var length = player.GetStringLength(x => x.Address1);
Or using the full static method for any other attribute...
或者对任何其他属性使用完整的静态方法......
var length = AttributeHelpers.GetPropertyAttributeValue<User,string,StringLengthAttribute,Int32>(prop => prop.Address1,attr => attr.MaximumLength);
Inspired by the answer here... https://stackoverflow.com/a/32501356/324479
受到这里答案的启发... https://stackoverflow.com/a/32501356/324479

