由于表达式,DropDownListFor在部分视图中失败

时间:2015-10-11 13:35:10

标签: c# asp.net-mvc

我正在使用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
        };
    })
)

如果在Test视图中使用以下版本接受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:Value不能为null或为空。 参数名称:名称]    System.Web.Mvc.Html.SelectExtensions.SelectInternal(HtmlHelper htmlHelper,ModelMetadata metadata,String optionLabel,String name,IEnumerable 1 selectList, Boolean allowMultiple, IDictionary 2 htmlAttributes)+589    System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper 1 htmlHelper, Expression 1表达式,IEnumerable 1 selectList, String optionLabel, IDictionary 2 htmlAttributes)+95    System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper 1 htmlHelper, Expression 1表达式,IEnumerable`1 selectList)+60    在c:\ visual studio 2015 \ Projects \ Test \ Test1 \ Views \ Shared \ EditorTemplates \ EnumList.cshtml中的ASP._Page_Views_Shared_EditorTemplates_EnumList_cshtml.Execute():3    System.Web.WebPages.WebPageBase.ExecutePageHierarchy()+197    System.Web.Mvc.WebViewPage.ExecutePageHierarchy()+ 105

如果在测试视图中直接调用DropDownListFor()并使用“m =&gt; m.State”之类的更改,那么它是有效的,所以我认为这个错误与“m =&gt; m”有关,但是什么是正确的表达呢?

提前感谢。

1 个答案:

答案 0 :(得分:0)

首先,您对DropDownListFor的使用是错误的(来自DropDownListFor帮助程序的MSDN描述):

  

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

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

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

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

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

例如,如果您的TestModel属于ParentTestModel的属性:

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

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

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

将模板渲染为部分视图时,Enum为模型

  1. 父前缀为空 - 通常部分视图不保留这些前缀,在这种特殊情况下根本没有前缀,因为它是顶级模型 和
  2. 属性名称为null - 因为m => m表达式基本上不选择任何属性
  3. 所以FullHtmlFieldNamenull。所以这段代码(SelectList助手的内部实现)引发了一个异常:

    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");
                } ...