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