编写一个简短的 HtmlHelper DropDownList 重载方法的类型问题
Type issue writing a short HtmlHelper DropDownList overloaded method
我正在尝试重载 DropDownListFor HtmlHelper 方法。
通常,参数 'htmlAttributes' 是一个匿名对象。如果 htmlAttributes 还不是 RouteValueDictionary,我会将其转换为这种类型,以便根据需要修改集合,基于我将添加的自定义逻辑,例如根据值处理禁用控件"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)
{
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);
}
我在最后一行调用 "native" System.Web.Mvc.Html.DropDownListFor 时遇到了问题 运行。当它期望一个匿名对象时,它没有正确处理 html 类型为 "RouteAttributes" 的属性。结果,我得到的 HTML 没有正确地将 routingAttributes 集合的 name/value html 属性转换为 nanme/value HTML 属性对。我明白了(注意 Keys 和 Values 属性):
例如,当我这样调用它时:
@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 类型的对象转换回匿名对象。我该怎么做呢?有没有更好的方法?
解决此问题的最佳方法是使用多个重载,就像内置 HtmlHelper
方法一样(请参阅 source code 了解 DropDownListFor()
方法)。
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
将无效。更好的方法是仅显示选定的文本值和隐藏的输入(假设您想要 post 该值)。
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>
元素(如果这是您想要的)。
我正在尝试重载 DropDownListFor HtmlHelper 方法。
通常,参数 'htmlAttributes' 是一个匿名对象。如果 htmlAttributes 还不是 RouteValueDictionary,我会将其转换为这种类型,以便根据需要修改集合,基于我将添加的自定义逻辑,例如根据值处理禁用控件"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)
{
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);
}
我在最后一行调用 "native" System.Web.Mvc.Html.DropDownListFor 时遇到了问题 运行。当它期望一个匿名对象时,它没有正确处理 html 类型为 "RouteAttributes" 的属性。结果,我得到的 HTML 没有正确地将 routingAttributes 集合的 name/value html 属性转换为 nanme/value HTML 属性对。我明白了(注意 Keys 和 Values 属性):
例如,当我这样调用它时:
@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 类型的对象转换回匿名对象。我该怎么做呢?有没有更好的方法?
解决此问题的最佳方法是使用多个重载,就像内置 HtmlHelper
方法一样(请参阅 source code 了解 DropDownListFor()
方法)。
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
将无效。更好的方法是仅显示选定的文本值和隐藏的输入(假设您想要 post 该值)。
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>
元素(如果这是您想要的)。