ASP.NET MVC2无法获取元素的完整id

时间:2011-09-05 12:19:05

标签: c# asp.net-mvc-2 model validation

我的模型有这种强类型的视图表单。问题是我似乎无法正确获取ID。我的视图模型中有表单模型,所以我必须调用一些元素:

<%: Html.TextBoxFor(m => m.Business.Business2)%>

问题在于此代码:

viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(partialFieldName)

如果我的partialFieldName是“Business2”,它应返回“Business_Business2”,但它只返回“Business2”。但是,如果我使用

<%: Html.EditorFor(x => x.Business) %>

它返回“Business_Business2”。我不能使用Html.EditorFor,因为我有css类放在我的表单元素上。没有正确的ID,我无法做很多客户端验证,所以这真的让我烦恼。有什么想法吗?

以下是我的代码:

模型

public class BusinessModel
    {
        public string Business1 { get; set; }
        public string Business2 { get; set; }
    }

    public class AccountModel
    {
        public string Account1 { get; set; }

        [MustMatch("Account1")]
        public string Account2 { get; set; }
    }

    public class SampleWrappedModel
    {
        public BusinessModel Business { get; set; }
        public AccountModel Account { get; set; }
    }

验证

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public sealed class MustMatchAttribute : ValidationAttribute
    {
        private const string DefaultErrorMessage = "Must match {0}";

        public MustMatchAttribute(string propertyToMatch)
            : base(DefaultErrorMessage)
        {
            PropertyToMatch = propertyToMatch;
        }

        public string PropertyToMatch { get; private set; }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, PropertyToMatch);
        }

        public override bool IsValid(object value)
        {
            throw new Exception("MustMatchAttribute requires the DataAnnotationsMustMatchValidator adapter to be registered"); 
        }
    }

    //Adapter class
    public class DataAnnotationsMustMatchValidator : DataAnnotationsModelValidator<MustMatchAttribute>
    {
        public DataAnnotationsMustMatchValidator(ModelMetadata metadata, ControllerContext context, MustMatchAttribute attribute)
            : base(metadata, context, attribute)
        {
        }

        public override System.Collections.Generic.IEnumerable<ModelValidationResult> Validate(object container)
        {
            var propertyToMatch = Metadata.ContainerType.GetProperty(Attribute.PropertyToMatch);
            if (propertyToMatch != null)
            {
                var valueToMatch = propertyToMatch.GetValue(container, null);
                var value = Metadata.Model;

                bool valid = Equals(value, valueToMatch);
                if (!valid)
                {
                    yield return new ModelValidationResult { Message = ErrorMessage };
                }
            }
        }

        public override System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            string propertyIdToMatch = GetFullHtmlFieldId(Attribute.PropertyToMatch);
            yield return new ModelClientMustMatchValidationRule(ErrorMessage, propertyIdToMatch);
        }

        private string GetFullHtmlFieldId(string partialFieldName)
        {
            ViewContext viewContext = (ViewContext)ControllerContext;
            return viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(partialFieldName);
        }
    }

    public class ModelClientMustMatchValidationRule : ModelClientValidationRule
    {
        public ModelClientMustMatchValidationRule(string errorMessage, string propertyIdToMatch)
        {
            ErrorMessage = errorMessage;

            ValidationType = "mustMatch";

            ValidationParameters.Add("propertyIdToMatch", propertyIdToMatch);
        }
    }

2 个答案:

答案 0 :(得分:0)

TemplateInfo对GetFullHtmlFieldName和GetFullHtmlFieldId方法的作用是将HtmlFieldPrefix添加到传递的partialFieldName之前。如果我理解正确,你需要一种能够从labmda表达式返回html字段名称的帮助器

 public static string GetHtmlFieldName<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
 {
     return ExpressionHelper.GetExpressionText(expression);
 }

然后你可以使用

Html.GetHtmlFieldName(m => m.Business.Business2)

这将返回Business.Business2

答案 1 :(得分:0)

  

我不能使用Html.EditorFor,因为我有css类放在我的表单元素上。

然后您可以编写自定义编辑器模板。所以在你看来:

<%: Html.EditorFor(x => x.Business) %>

然后在~/Views/Shared/EditorTemplates/BusinessModel.ascx内:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BusinessModel>" %>
<%: Html.TextBoxFor(m => m.Business1) %>
<%: Html.TextBoxFor(m => m.Business2) %>
...

或者如果您不喜欢模板的传统地点和名称,您也可以自定义它:

<%: Html.EditorFor(x => x.Business, "MyBusinessTemplate") %>

或者如果只是在输入元素中应用其他属性,则可以更优雅的方式执行:writing a custom DataAnnotationsModelMetadataProvider

我建议您始终使用EditorFor代替TextBoxFor