我正在试验定制的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提供程序来弥补这一差距?
编辑:我开始倾向于认为这是框架中的一个bug。
考虑两段代码:
@Html.DropDownListFor(model => model.ErrorData.Shift, Model.ShiftOptions, new { @class = "form-control" })
上面的代码传入选项"Model.ShiftOptions“。因此,它不会传递条件"selectList==null“,因此”标志“永远不会设置,而是继续尝试通过反射( Eval调用)从类型获取默认值。
但是,使用此代码:
@{ ViewData[Html.NameFor(m => m.ErrorData.Shift).ToString()] = Model.ShiftOptions;}
@Html.DropDownListFor(model => model.ErrorData.Shift,null, new { @class = "form-control" })
.“标志”现在被满足,默认值现在被检索到metadata.Model。为什么提供列表选项的不同机制会改变(甚至影响)从其中检索默认值的位置?
编辑#2
警告:如果在编辑器模板( ViewData )中调用复杂类型的DropDownListFor,上述DropDownListFor“修复”将无法工作。NameFor调用将返回属性的名称,包括从EditorFor调用的外部上下文,即MyViewModel.ErrorData.Shift。但是,顶部的原始代码片段中的DropDownListFor代码查找的是没有原始上下文的ViewData项,即ErrorData.Shift。他们都用
ExpressionHelper.GetExpressionText((LambdaExpression) expression)
但是,NameOf对该结果使用html.Name。当DDLF最终开始生成它的名称时,它会做一些类似的事情,因此它的名称是正确的,但是在查找视图数据选项时,它不包括它的完整上下文是没有意义的。
发布于 2016-05-13 17:52:14
用于生成表单的所有HtmlHelper
方法首先检查ModelState
( GetModelStateValue()
方法)中是否存在属性的值,以处理表单被提交时使用无效值并返回视图的情况(请参阅这个答案的第2部分,以解释为什么这是默认行为)。
例如,在使用DropDownList()
的情况下
@Html.DropDownList("xxx", null, "--Please select--")
如果xxx
是作为ViewBag
属性添加的IEnumerable<SelectListItem>
,则selectList
的值为null
,执行第一个if
块中的代码,flag
的值为true
(还请注意,模型可能有或可能没有一个名为xxx
的属性,这意味着< code >D15可能是null
)。
或者,如果您使用强类型的DropDownListFor()
方法,例如
@Html.DropDownListFor(m => m.SomeProperty, Model.SomePropertyList, "--Please select--")
selectList
的值不是null
(假设SomePropertyList
是IEnumerable<SelectListItem>
而不是null
),flag
的值是false
。
因此,各种检查只是考虑了使用DropDownList()
或DropDownListFor()
生成<select>
元素的不同方式,以及是否绑定到模型属性。
附带注意:实际代码(来自私有静态MvcHtmlString SelectInternal()方法)是bool usedViewData = false;
,而不是bool flag = false;
https://stackoverflow.com/questions/37213368
复制相似问题