DropDownListFor failed in partial view due to expression

I'm using Visual Studio 2015 community edition for ASP.net MVC project testing, Here is my simple model:

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

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

public enum TestState
{
    eNone,
    eNew,
    eFinished,
}

Here is a generic 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
        };
    })
)

it works fine if below is used in Test view which accepts TestModel as model.

@Html.EditorForModel()

However when I try to use above EnumList.cshtml via specific action as below:

@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);
}

I got following errors:

Value cannot be null or empty. Parameter name: name

below is from the stack trace:

[ArgumentException: Value cannot be null or empty. Parameter name: name] 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 expression, IEnumerable 1 selectList, String optionLabel, IDictionary 2 htmlAttributes) +95 System.Web.Mvc.Html.SelectExtensions.DropDownListFor(HtmlHelper 1 htmlHelper, Expression 1 expression, IEnumerable`1 selectList) +60 ASP._Page_Views_Shared_EditorTemplates_EnumList_cshtml.Execute() in c:visual studio 2015ProjectsTestTest1ViewsSharedEditorTemplatesEnumList.cshtml:3 System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197 System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +105

It works if above DropDownListFor() is called directly in Test view with changes like "m => m.State", so I believe this error to do with "m => m", but what is the correct expression then?

thanks in advance.


First of all your usage of DropDownListFor is wrong (from the MSDN description of DropDownListFor helpers ):

Returns an HTML select element for each property in the object that is represented by the specified expression using the specified list items.

You are using it for the model itself and not for model properties!

Explanation why your approach works with view which accepts TestModel as model and doesn't work as a separate partial view:

By default editor templates generate id and name properties for it's inputs as a combination of parent prefix(see examples) with the current model property name. For example when you use TestModel as the main model for your view and the use @Html.EditorForModel() , the name and the id of you select will be State :

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

If for example your TestModel is a property of ParentTestModel :

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

Then your editor template will be rendered as

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

When you render a template as a partial view with Enum as model both

  • parent prefix is null - in general partial views don't preserve those prefixes and in this particular case there is no prefix at all because its a top model and
  • property name is null - because of m => m expression which basically doesn't select any property
  • so FullHtmlFieldName is null . So this code (internal implementation of SelectList helpers ) throws an exception:

    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");
                } ...
    
    链接地址: http://www.djcxy.com/p/19090.html

    上一篇: c#mvc助手扩展Html.DisplayFor

    下一篇: 由于表达式的原因DropDownListFor在局部视图中失败