我也做过类似的事情
我声明了两个类,一个用于模型,一个用于保存下拉列表的每个选项标签的值
public Class Report
{
public ReportName {get; set;}
public IList<ReportSummaryModel> AvailableReports {get; set;}
}
public class ReportSummaryModel
{
public ReportActualName {get; set;}
public ReportClassName {get; set;}
public TextField {get; set;}
public ValueField {get; set;}
}
我想将 ReportActualName 和 ReportClassName 输出到下拉列表的选项标签上,这些值因每个选项而异。
所以我在下面写了 HTML 辅助函数
public static MvcHtmlString DropDownList<TPageModel, TSelectListModel, TProperty>(this HtmlHelper<TPageModel> htmlHelper,
Expression<Func<TPageModel, TProperty>> expression, IEnumerable<TSelectListModel> selectList, Expression<Func<TSelectListModel, TProperty>> textField,
Expression<Func<TSelectListModel, TProperty>> valueField, string optionLabel, IDictionary<string, Expression<Func<TSelectListModel, TProperty>>> optionsAttributes)
下面会提到实际的函数调用
@Html.DropDownList(x => x.ReportName,
Model.AvailableReports,
x => x.TextField,
x => x.ValueField,
"-- Select --",
new Dictionary<string, Expression<Func<ReportSummaryModel, object>>>{ {"data-name", x => x.ReportActualName}, {"data-class", x => x.ReportClassName}})
其余的效用函数如下所述
public static MvcHtmlString DropDownList<TPageModel, TSelectListModel, TProperty>(this HtmlHelper<TPageModel> htmlHelper, Expression<Func<TPageModel, TProperty>> expression, IEnumerable<TSelectListModel> selectList, Expression<Func<TSelectListModel, TProperty>> textField, Expression<Func<TSelectListModel, TProperty>> valueField, string optionLabel, IDictionary<string, Expression<Func<TSelectListModel, TProperty>>> optionsAttributes)
{
string name = ExpressionHelper.GetExpressionText(expression);
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
string defaultValue = string.Empty;
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
{
if (modelState.Value != null)
{
defaultValue = (string)modelState.Value.ConvertTo(typeof(string), null /* culture */);
}
}
var listItemBuilder = new StringBuilder();
// Make optionLabel the first item that gets rendered.
if (optionLabel != null)
{
listItemBuilder.AppendLine(ListItemToOption(optionLabel, string.Empty, false, null));
}
/* Loop through each options
* Convert each ListItem to an <option> tag */
foreach (var listItem in selectList)
{
string text = listItem.GetType()
.GetProperties()
.Single(p => p.Name.Equals(ClassHelper.PropertyName(textField)))
.GetValue(listItem, null)
.ToString();
string value = listItem.GetType()
.GetProperties()
.Single(p => p.Name.Equals(ClassHelper.PropertyName(valueField)))
.GetValue(listItem, null)
.ToString();
bool isSelected = value.Equals(defaultValue);
var htmlAttributes = new Dictionary<string, string>();
foreach (var option in optionsAttributes)
{
string propertyName = ClassHelper.PropertyName(option.Value);
htmlAttributes.Add(option.Key, listItem.GetType()
.GetProperties()
.Single(p => p.Name.Equals(propertyName))
.GetValue(listItem, null)
.ToString());
}
listItemBuilder.AppendLine(ListItemToOption(text, value, isSelected, htmlAttributes));
}
var tagBuilder = new TagBuilder("select")
{
InnerHtml = listItemBuilder.ToString()
};
tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
}
//Private method copied from mvc built in helper to generate option attribute
internal static string ListItemToOption(string text, string value, bool isSelected, IDictionary<string, string> htmlAttributes)
{
var builder = new TagBuilder("option")
{
InnerHtml = HttpUtility.HtmlEncode(text)
};
if (value != null)
{
builder.Attributes["value"] = value;
}
if (isSelected)
{
builder.Attributes["selected"] = "selected";
}
if (htmlAttributes != null)
{
builder.MergeAttributes(htmlAttributes);
}
return builder.ToString(TagRenderMode.Normal);
}
//Utility function to get property name
public class ClassHelper
{
public static string PropertyName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
var body = expression.Body as MemberExpression;
if (body == null)
{
body = ((UnaryExpression)expression.Body).Operand as MemberExpression;
}
return body.Member.Name;
}
}
输出是
<select name="ReportName">
<option>--Select--</option>
<option value="1" data-name="NameA" data-class="classA">A</option>
<option value="2" data-name="NameB" data-class="classB">B</option>
<option value="3" data-name="NameC" data-class="classC">C</option>
<option value="4" data-name="NameD" data-class="classD">D</option>
</select>