开发者

ASP.NET MVC2 Can't get full id of element

开发者 https://www.devze.com 2023-04-02 18:57 出处:网络
I have this strongly typed view form for my model. Problem is that I can\'t seem to get the IDs right. My view model has form models within it so I have to call some elements like:

I have this strongly typed view form for my model. Problem is that I can't seem to get the IDs right. My view model has form models within it so I have to call some elements like:

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

Problem is with this code:

viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(partialFieldName)

If my partialFieldName is "Business2" it should return "Business_Business2" but it only returns "Business2". However, if I use

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

it returns "Business_Business2". I can't use Html.EditorFor since I have css classes to place on my form elements. I can't do much of my client side validations without the right Id so this has really been bugging me. Any ideas?

Here are my codes:

Models

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; }
    }

Validations

[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)
            {
         开发者_StackOverflow中文版       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);
        }
    }


What the TemplateInfo does with GetFullHtmlFieldName and GetFullHtmlFieldId methods, is simply prepending HtmlFieldPrefix to passed partialFieldName. If I understood correctly, you need kind of helper able to return html field name from labmda expression

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

And then you could use

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

This will return Business.Business2


I can't use Html.EditorFor since I have css classes to place on my form elements.

You could write a custom editor template then. So in your view:

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

and then inside ~/Views/Shared/EditorTemplates/BusinessModel.ascx:

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

or if you don't like the conventional places and names for templates you could customize that as well:

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

or if it is only a matter of applying additional attributes to your input elements you could do it in an even more elegant way: by writing a custom DataAnnotationsModelMetadataProvider.

I would recommend you to always use EditorFor instead of TextBoxFor.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号