我正在尝试重载DropDownListFor HtmlHelper方法。
通常,参数'htmlAttributes'将是一个匿名对象。如果htmlAttributes还不是RouteValueDictionary,我会根据我要添加的自定义逻辑将其转换为此类型,以便根据需要修改集合,例如根据“禁用”的值处理禁用控件参数值,仅作为一个例子。
public static MvcHtmlString DropDownListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
object htmlAttributes,
bool disabled)
{
if (!(htmlAttributes is RouteValueDictionary))
{
htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
}
else
{
htmlAttributes = (RouteValueDictionary)htmlAttributes;
}
if (disabled)
{
//manipulate the htmlAttributes collection here
}
return htmlHelper.DropDownListFor(expression, selectList, optionLabel, htmlAttributes);
}
当我在最后一行调用“本机”System.Web.Mvc.Html.DropDownListFor时遇到问题。当它期望Anonymous对象时,它无法正确处理类型为“RouteAttributes”的htmlAttributes。因此,我得到的HTML没有正确地将routingAttributes集合的名称/值html属性转换为nanme / value HTML属性对。我明白了(注意键和值属性):
例如,当我用它调用它时:
@Html.DropDownListFor(model => model.FrequencyCode, Model.FrequencyCodes.ToListOfSelectListItem(Model.FrequencyCode), "", new { @class = "form-control" }, true)
我明白了:
<input data-val="true" data-val-required="Frequency is required" id="FrequencyCode" name="FrequencyCode" type="hidden" value="" />
<select Count="1" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" id="FrequencyCode" name="FrequencyCode">
<option value=""></option>
<option value="A">ANNUAL</option>
<option value="M">MONTHLY</option>
<option value="Q">QUARTERLY</option>
</select>
似乎解决这个问题的一种方法是,如果我可以将RouteDictionary类型的对象转换回匿名对象。我该怎么做呢?还有更好的方法吗?
答案 0 :(得分:1)
解决此问题的最佳方法是进行多次重载,就像内置HtmlHelper
方法一样(请DropDownListFor()
方法引用source code)。
public static MvcHtmlString DropDownListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
IDictionary<string, object> htmlAttributes,
bool disabled)
public static MvcHtmlString DropDownListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
object htmlAttributes,
bool disabled)
然而,生成一个禁用的<select>
元素没有多大意义 - 你生成了许多额外的不必要的html,并且禁用的控件不提交那里的值,因此模型绑定可能会失败,如果方法是绑定到值类型的属性,或具有验证属性,ModelState
将无效。更好的方法是仅显示所选文本值和隐藏输入(假设您要发布值)。
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes, bool disabled)
{
if (disabled)
{
StringBuilder html = new StringBuilder();
// add a hidden input
html.Append(htmlHelper.HiddenFor(expression).ToString());
// Get the display text
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
string value = metaData.Model.ToString();
var displayText = selectList.Where(x => x.Value == value).Select(x => x.Text).FirstOrDefault();
TagBuilder div = new TagBuilder("div");
div.AddCssClass("readonly");
div.InnerHtml = displayText;
html.Append(div.ToString());
return MvcHtmlString.Create(html.ToString());
}
return htmlHelper.DropDownListFor(expression, selectList, optionLabel, htmlAttributes);
}
然后使用css将.readonly
样式设置为<input />
或<select>
元素,如果这是你想要的。