3

我正在开发一个 ASP.NET MVC3 应用程序,我无法让 DropDownListFor 在特定的编辑器视图中使用我的属性。

我的模型是一个Person,一个人有一个属性,指定它是“人类型”。PersonType是一个包含名称/描述和 ID 的类。我可以PersonType通过名为ApplicationSettings.

在我的编辑模板视图中,我Person创建了一个SelectList用于调试目的:

@ModelType MyNamespace.Person
@Code
    Dim pTypesSelectList As New SelectList(MyNamespace.ApplicationSettings.PersonTypes, "ID", "Name", Model.PersonType.ID)
End Code

然后我将此SelectList作为参数提供给DropDownListFor绑定到PersonType我的属性的Person.

为了调试目的,我还打印了Selected每个项目的属性:SelectList

<div style="text-align: center; margin: 5px 0 0 0;">
    <div>
        @Html.LabelFor(Function(model) model.PersonType)
    </div>
    <div>
        @Html.DropDownListFor(Function(model) model.PersonType, pTypesSelectList)
        @Html.ValidationMessageFor(Function(model) model.PersonType)

        <br />
        <br />
        <!-- The following is debugging code that shows the actual value-->
        @Model.Type.Name
        <br />
        @Model.Type.ID
        <br />
        <br />

        <!--This section is to show that the select list has properly selected the value-->
        @For Each pitem In pTypesSelectList
            @<div>
                @pitem.Text selected: @pitem.Selected
            </div>
        Next
    </div>
</div>

该视图绑定到PersonPersonType属性为“Person Type # 2”的一个,我希望它被选中;但是此代码的 HTML 输出如下所示:

<div style="text-align: center; margin: 5px 0 0 0;">
    <div>
    <label for="PersonType">PersonType</label>
    </div>
    <div>
        <select id="PersonType" name="PersonType">
            <option value="7e750688-7e00-eeee-0000-007e7506887e">Default Person Type</option>
            <option value="87e5f686-990e-5151-0151-65fa7506887e">Person Type # 1</option>
            <option value="a7b91cb6-2048-4b5b-8b60-a1456ba4134a">Person Type # 2</option>
            <option value="8a147405-8725-4b53-b4b8-3541c2391ca9">Person Type # 3</option>
        </select>
        <span class="field-validation-valid" data-valmsg-for="PersonType" data-valmsg-replace="true"></span>
        <br />
        <br />
        <!-- The following is debugging code that shows the actual value-->
        Person Type # 2
        <br />
        a7b91cb6-2048-4b5b-8b60-a1456ba4134a
        <br />
        <br />
        <!--This section is to show that the select list has properly selected the value-->
        <div>
            Default Person Type selected: False
        </div>
        <div>
            Person Type # 1 selected: False
        </div>
        <div>
            Person Type # 2 selected: True
        </div>
        <div>
            Person Type # 3 selected: False
        </div>
    </div>
</div>

如您所见,SelectList 中项目的打印 Selected 属性显示第三个项目是“Selected”。但让我抓狂的是,与此相对应的选项是未选择。

4

2 回答 2

6

通常,除非没有其他选项,否则 HTML 助手将完全忽略Selectedin 的属性。SelectList如果DropDownListFor可以通过其他方式找到该值,它将坚持使用该值。

在这种情况下,它将使用model.PersonType( .ToString()) 的值——但这不是你想要的,根据model.PersonType.ID你传递给SelectList.

更多信息在此处的答案中。

解决方法

一种应该有效的简单解决方法是设置:

ViewData["PersonType"] = model.PersonType.Id. 

如果 ModelState 存在,助手首先查看它——即在 POST 上。这应该已经有效,因为ModelState["PersonType"]将使用发布的实际选定值填充。

在 ModelState 之后,它会先查看ViewData- with ViewData["PersonType"],然后才查看ViewData.Model.PersonType。换句话说,您可以使用直接设置在模型上的值“覆盖”模型上的值ViewData

更好的 (IMO) 解决方案

更一般的“更好的做法”,解决它的方法(也避免使用自定义模型绑定器以将 POST'ed ID 转换回PersonType)是使用 ViewModel 而不是在视图中使用完整模型:

  • 拥有一个PersonTypeID属性 - 而不是PersonType.
  • 填充它PersonType.ID
  • 在您的视图中使用它
    • VB.NET:Html.DropDownListFor(Function(model) model.PersonTypeID)
    • C#:Html.DropDownListFor(model => model.PersonTypeID)
  • 当表单被 POST 后,将 ViewModel(包括PersonTypeID=> PersonType)转换回您的 POST 操作中的实际模型。

这似乎需要更多工作,但通常在项目中往往有很多情况下您需要更多特定于视图的数据表示以避免过多的内联 Razor 代码 - 因此从业务对象转换为视图模型,虽然看起来有时是多余的和反干燥的,往往会让你免于很多头痛。

于 2013-08-20T14:25:12.917 回答
1

您确定在渲染视图之前您的“PersonType”键的 ModelState 是空的吗?正如 JimmiTh 所说,将首先在 ModelState 中搜索值。它也发生在我身上,你可以尝试 @Html.DropDownList("PersonTypeFake", Function(model) model.PersonType, pTypesSelectList),它应该选择正确的选项。

于 2013-08-16T20:59:42.337 回答