【问题标题】:DropDownListFor failed in partial view due to expression由于表达式,DropDownListFor 在部分视图中失败
【发布时间】:2015-10-11 13:35:09
【问题描述】:

我正在使用 Visual Studio 2015 社区版进行 ASP.net MVC 项目测试, 这是我的简单模型:

public class TestModel
{
    [Required]
    public string Name { get; set; }

    [UIHint("EnumList")]
    public TestState State { get; set; }
}

public enum TestState
{
    eNone,
    eNew,
    eFinished,
}

这是一个通用的 html - EnumList.cshtml

@model Enum

@Html.DropDownListFor(m => m, Enum.GetValues(Model.GetType()).OfType<Enum>()
    .Select(m =>
    {
        string enumVal = Enum.GetName(Model.GetType(), m);
        return new SelectListItem()
        {
            Selected = (Model.ToString() == enumVal),
            Text = enumVal,
            Value = enumVal
        };
    })
)

如果在接受 TestModel 作为模型的测试视图中使用下面的内容,它可以正常工作。

@Html.EditorForModel()

但是,当我尝试通过以下特定操作使用上面的 EnumList.cshtml 时:

@Html.Action("Enum", new { pState = Model.State });     <-- used in View html

// below action will be called by above method
[ChildActionOnly]
public PartialViewResult Enum(TestState? pState)
{
    return PartialView("~/Views/Shared/EditorTemplates/EnumList.cshtml", pState.HasValue ? pState.Value : TestState.eNone);
}

我收到以下错误:

值不能为 null 或空。 参数名称:名称

以下来自堆栈跟踪:

[ArgumentException:值不能为空或空。 参数名称:名称] System.Web.Mvc.Html.SelectExtensions.SelectInternal(HtmlHelper htmlHelper,ModelMetadata 元数据,字符串 optionLabel,字符串名称,IEnumerable1 selectList, Boolean allowMultiple, IDictionary2 htmlAttributes)+589 System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper1 htmlHelper, Expression1 表达式,IEnumerable1 selectList, String optionLabel, IDictionary2 htmlAttributes) +95 System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper1 htmlHelper, Expression1 表达式,IEnumerable`1 selectList) +60 c:\visual studio 2015\Projects\Test\Test1\Views\Shared\EditorTemplates\EnumList.cshtml:3 中的 ASP._Page_Views_Shared_EditorTemplates_EnumList_cshtml.Execute() System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197 System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +105

如果在测试视图中直接调用上面的 DropDownListFor() 并进行“m => m.State”之类的更改,它会起作用,所以我相信这个错误与“m => m”有关,但是正确的表达式是什么?

提前致谢。

【问题讨论】:

  • @Html.EditorFor(m=&gt;m.State,"EnumList")代替@Html.Action("Enum", new { pState = Model.State });
  • 关于 SO 上的 DropDownLists 的问题太多了。

标签: c# asp.net-mvc


【解决方案1】:

首先你对 DropDownListFor 的使用是错误的(来自 DropDownListFor helpers 的 MSDN 描述):

为使用指定列表项的指定表达式表示的对象中的每个 属性 返回一个 HTML 选择元素。

您将它用于模型本身而不是模型属性!

解释为什么您的方法适用于接受 TestModel 作为模型并且不能作为单独的局部视图工作的视图:

默认情况下,编辑器模板会为其输入生成 id 和 name 属性,作为父前缀(参见示例)与当前模型属性名称的组合。例如,当您使用TestModel 作为视图的主模型并使用@Html.EditorForModel() 时,您选择的名称和id 将是State

&lt;select name="State" id="State"&gt;....

例如,如果您的 TestModelParentTestModel 的属性:

public class ParentTestModel
{
    public TestModel TestModelProperty {get;set;}
}

然后你的编辑器模板将呈现为

<select name="TestModelProperty.State" id="TestModelProperty_State">...

当您将模板渲染为局部视图,Enum 作为模型时

  1. 父前缀为空 - 通常部分视图不保留这些前缀,在这种特殊情况下根本没有前缀,因为它是顶级模型 和
  2. 属性名称为空 - 因为m =&gt; m 表达式基本上不选择任何属性

所以FullHtmlFieldNamenull。所以这段代码(SelectList helpers 的内部实现)会抛出异常:

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
            string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
            IDictionary<string, object> htmlAttributes)
        {
            string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            if (String.IsNullOrEmpty(fullName))
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
            } ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    相关资源
    最近更新 更多