我尝试使用自定义ModelMetadataProvider。似乎像TextBoxFor这样的一些html助手使用这些就好了。但是,在DropDownListFor等其他情况下,他们更喜欢使用ViewData。例如,看一些反映的代码,我看到:
bool flag = false;
if (selectList == null)
{
selectList = SelectExtensions.GetSelectData(htmlHelper, name);
flag = true;
}
object defaultValue = allowMultiple ? htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof (string[])) : htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof (string));
if (defaultValue == null && !string.IsNullOrEmpty(name))
{
if (!flag)
defaultValue = htmlHelper.ViewData.Eval(name);
else if (metadata != null)
defaultValue = metadata.Model;
}
注意获得" defaultValue"的所有不同尝试。使用metadata.Model已经过时了。为什么在这里分离?如果你追踪那段代码,你最终会调用ViewData.Eval,而后者只是使用反射来获取模型中的值。是否存在自定义ViewData提供程序以弥合这一差距?
编辑:我开始倾向于认为这是框架中的错误。考虑两段代码:
@Html.DropDownListFor(model => model.ErrorData.Shift, Model.ShiftOptions, new { @class = "form-control" })
上面的代码传递了选项" Model.ShiftOptions"。因此,它没有通过条件" selectList == null"因此" flag"永远不会设置,而是继续尝试通过反射(Eval调用)从类型中获取默认值。
但是使用此代码:
@{ ViewData[Html.NameFor(m => m.ErrorData.Shift).ToString()] = Model.ShiftOptions;}
@Html.DropDownListFor(model => model.ErrorData.Shift,null, new { @class = "form-control" })
..."标志"现在已满足,现在检索默认值metadata.Model。 为什么提供列表选项的不同机制会从中检索默认值(?/ / strong>
)?答案 0 :(得分:1)
生成表单控件的所有HtmlHelper
方法首先检查ModelState
(GetModelStateValue()
方法)中是否存在属性值,以处理表单已提交的情况使用无效值并返回视图(请参阅this answer的第2部分,以获取解释此为默认行为的原因)。
如果您使用DropDownList()
,例如
@Html.DropDownList("xxx", null, "--Please select--")
xxx
IEnumerable<SelectListItem>
已添加为ViewBag
属性,selectList
的值为null
,第一个if
中的代码1}}块被执行,flag
的值为true
(并且还注意该模型可能有也可能没有名为xxx
的属性,这意味着metadata
可能是null
)
或者,如果您使用强类型DropDownListFor()
方法,例如
@Html.DropDownListFor(m => m.SomeProperty, Model.SomePropertyList, "--Please select--")
selectList
的值不是null
(假设SomePropertyList
是IEnumerable<SelectListItem>
而不是null
)和flag
的值是false
因此,各种检查只考虑了使用DropDownList()
或DropDownListFor()
生成<select>
元素的不同方式,以及是否绑定到模型属性或不。
附注:实际代码(来自private static MvcHtmlString SelectInternal()方法)为bool usedViewData = false;
,而不是bool flag = false;