Question

I've searched all around, read all the posts related to creating a strongly typed helper, but none have addressed my issue. Problem:

When referencing a simple property, all works well:

@Html.TextBoxGroupFor(x => x.BadgeNumber)

When trying to access properties on a different class in my model, I get an error:

@Html.TextBoxGroupFor(x => x.Person.BadgeNumber)

The error is:

The property InspectionEditViewModel.Person.BadgeNumber could not be found.

The problem line is:

var metaData = ModelMetadataProviders.Current.GetMetadataForProperty(() => Activator.CreateInstance<TModel>(), typeof(TModel), displayName);

I'm guessing it has to do with the GetMetadataForProperty not being able to find BadgeNumber on InspectionEditViewModel. MVC's HTML helpers by default are able to do this with no problems.

EDIT:

I knew I left something out, it's been a long day. Here is the Helpers code:

public static MvcHtmlString TextBoxGroupFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
                                                     Expression<Func<TModel, TProperty>> expression)
        {
            var inputName = ExpressionHelper.GetExpressionText(expression);
            var fullHtmlFieldName = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(inputName);
            var metaData = ModelMetadataProviders.Current.GetMetadataForProperty(() => Activator.CreateInstance<TModel>(), typeof(TModel), fullHtmlFieldName);
            var displayName = metaData.DisplayName ?? inputName;
            return TextBoxGroup(helper, displayName, inputName);
        }
Was it helpful?

Solution

ModelMetadata.FromLambdaExpression(propertyExpression, html.ViewData);

This is what you are looking for. Unfortunately, this means that html must be an instance of HtmlHelper from a view whose model is the type you're trying to get the metadata for.

I think that's because it wants to take the property values from the Model/ViewData and pass it by the ModelMetadataProvider to allow it to to populate metadata specific to the model instance in question.

If you don't care about instance-specific metadata (eg: only want data annotation attributes) and so on, then just pass it a new ViewDataDictionary (where TModel is the type whose metadata you want to get).

For bonus feel-good points, the FromLambdaExpression method caches expressions and their resolved property paths inside it to give better performance.

Hope that helps you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top