【问题标题】:Binding to a SelectList in MVC在 MVC 中绑定到 SelectList
【发布时间】:2010-05-26 22:01:51
【问题描述】:

我又一次遇到了“这不应该是这样吗?*!# 困难”的情况。

问题:我想在 MVC 中使用表单来创建对象。对象的一个​​元素是一组有限的选择——下拉列表的完美候选者。

但是,如果我在我的模型中使用 SelectList,并在我的视图中使用下拉列表,然后尝试将模型发布回我的 Create 方法,我会收到错误“Missing Method Exception:No Parameterless constructor for this object ”。探索MVC源代码,看来为了绑定模型,Binder必须能够先创建它,并且它不能创建SelectList,因为它没有默认构造函数。

这是简化的代码: 对于模型:

public class DemoCreateViewModel
{
    public SelectList Choice { get; set; }
}

对于控制器:

//
// GET: /Demo/Create

public ActionResult Create()
{
    DemoCreateViewModel data = new DemoCreateViewModel();
    data.Choice = new SelectList(new string[] { "Choice1", "Choice2", "Choice3" });
    ViewData.Model = data;
    return View();
}

//
// POST: /Demo/Create

[HttpPost]
public ActionResult Create(DemoCreateViewModel form)
{
    try
    {
        // TODO: Add insert logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

对于视图:

<fieldset>
    <legend>Fields</legend>
    <%= Html.LabelFor(model => model.Choice) %>
    <%= Html.DropDownListFor(model => model.Choice, Model.Choice) %>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>

现在,我知道我可以通过后退 10 码并下注来完成这项工作:绕过模型绑定并返回到 FormCollection 并自己验证和绑定所有字段,但必须有一个更简单的方法。我的意思是,这是一个尽可能简单的要求。有没有办法在 MVC ModelBinding 架构中完成这项工作?如果是这样,它是什么?如果没有,怎么会?

编辑:嗯,我脸上有鸡蛋,但也许这对其他人有帮助。我做了更多的试验,发现了一个似乎可行的简单解决方案。

提供一个简单值(字符串或整数,具体取决于您的选择列表值类型),并将其命名为您绑定到的模型元素。然后提供第二个元素作为选项的选择列表,并将其命名为其他名称。所以我的模型变成了:

public class DemoCreateViewModel
{
    public string Choice { get; set; }
    public SelectList Choices { get; set; }
}

然后View中的DropDownListFor语句就变成了:

<%= Html.DropDownListFor(model => model.Choice, Model.Choices) %>

当我这样做时,提交按钮正确地将表单中的选择绑定到字符串 Choice,并将模型提交回第二个 Create 方法。

【问题讨论】:

  • 感谢您发布修复,我遇到了类似的问题,您的编辑帮助了
  • 你不能只将它绑定到一个 IEnumerable 或 SelectListItems 列表吗?

标签: asp.net-mvc model-binding selectlist


【解决方案1】:

这是一种方法:

@Html.DropDownListFor(model => model.Choice, 
                      ViewBag.Choices as SelectList, 
                      "-- Select an option--",
                      new { @class = "editor-textbox" })

请注意,我使用 ViewBag 来包含我的 SelectList。这样,当您回发时,客户端不会将整个选择列表作为模型的一部分发送到服务器。

在你的控制器代码中,你只需要设置视图包:

ViewBag.Choices = new SelectList(....

【讨论】:

  • 请注意,我使用 ViewBag 来包含我的 SelectList。这样,当您回发时,客户端不会将整个选择列表作为模型的一部分发送到服务器。 (1) 无论如何都不会; (2) 如果确实如此,使用 ViewBag 不会阻止它被发布,它只会阻止它绑定到模型。
【解决方案2】:

考虑为您的 post 操作创建一个不带 SelectList 属性的不同视图模型:

            public class DemoCreateViewModelForUpdate
            {
                public string Choice { get; set; }
            }

然后,如果模型状态无效并且您想重新显示视图,您始终可以从 DemoCreateViewModelPost 实例映射到 DemoCreateViewModel 实例。我倾向于将视图所需的所有内容都放在我的显示视图模型类中,因此使用单独的仅更新视图模型让我保持苗条和修剪,以便返回服务器。

在你看来,你会这样做:

            @Html.DropDownListFor(m => m.Choice, Model.Choices)

与上一个答案一样,因此不会有不必要的数据往返。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多