I am trying to create a Html Helper which takes two model properties. In my example below my model has two fields Height and HeightUnit. The code in the helper will render a Bootstrap textbox with a drop down list of units in an input group. The first model property is bound to the textbox and the second is bound to the drop down list. The code does not error on compile but when it gets the display name of the 2nd expression it fails with the following error:
"Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."
Here is the Html Helper declaration:
public static MvcHtmlString MaterialTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> textBoxExpression, Expression<Func<TModel, TValue>> dropDownListExpression, object htmlAttributes = null)
{
string Id = htmlHelper.IdFor(textBoxExpression).ToString();
string DisplayName = htmlHelper.DisplayNameFor(textBoxExpression).ToString();
// this is coming out as blank
string DDId = htmlHelper.IdFor(dropDownListExpression).ToString();
// this is causing the error message displayed
string DDDisplayName = htmlHelper.DisplayNameFor(dropDownListExpression).ToString();
}
Here is the razor code I am trying to use to call the helper:
@Html.MaterialTextBoxFor(m => m.Height, m => m.HeightUnit)
Does anyone know how to make this work?
I eventually did find a solution. The key was to not use a second expression for the data source. Instead to create the source as an item in the model but pass it directly to the helper.
public static MvcHtmlString CustomDropDownListFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, List<SelectListItem> DataSource, object htmlAttributes = null)
Inside the model you need to have two fields, one to store the selected value and one for holding the source data:
public string MyField{ get; set; }
public List<SelectListItem> MyFieldSource { get; set; }
You then call the helper as follows:
@Html.CustomDropDownListFor(m => m.MyField, Model.MyFieldSource)
I populate the "source" fields in the model constructor.