HtmlHelper中的元数据与ViewData

时间:2016-05-13 15:00:16

标签: asp.net-mvc

我尝试使用自定义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>

)?

1 个答案:

答案 0 :(得分:1)

生成表单控件的所有HtmlHelper方法首先检查ModelStateGetModelStateValue()方法)中是否存在属性值,以处理表单已提交的情况使用无效值并返回视图(请参阅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(假设SomePropertyListIEnumerable<SelectListItem>而不是null)和flag的值是false

因此,各种检查只考虑了使用DropDownList()DropDownListFor()生成<select>元素的不同方式,以及是否绑定到模型属性或不。

附注:实际代码(来自private static MvcHtmlString SelectInternal()方法)为bool usedViewData = false;,而不是bool flag = false;