【问题标题】:On Post, a drop down list SelectList.SelectedValue is null在 Post 上,下拉列表 SelectList.SelectedValue 为空
【发布时间】:2012-04-24 08:59:31
【问题描述】:

我的模型如下:

public class testCreateModel
{
    public string s1 { get; set; }
    public SelectList DL { get; set; }

    public testCreateModel()
    {
        Dictionary<string, string> items = new Dictionary<string, string>();
        items.Add("1", "Item 1");
        items.Add("2", "Item 2");
        DL = new SelectList(items, "Key", "Value");
    }
}

我的初始操作是:

    public ActionResult testCreate()
    {
        testCreateModel model = new testCreateModel();
        return View(model);
    }

我的 Razor 视图(已删除无关部分)是:

@model Tasks.Models.testCreateModel

@using (Html.BeginForm()) {
<fieldset>
    <legend>testCreateModel</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.s1)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.s1)
    </div>

    <div class="editor-label">
        Select an item:
    </div>
    <div class="editor-field">
        @Html.DropDownList("dropdownlist", (SelectList)Model.DL)
    </div>

    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

回发动作是:

    public ActionResult testCreate(testCreateModel model, FormCollection collection)
    {
        if (ModelState.IsValid)
        {
            Console.WriteLine("SelectedValue: ",model.DL.SelectedValue);
            Console.WriteLine("FormCollection:", collection["dropdownlist"]);
            // update database here...
        }
        return View(model);
    }

回发时,model.DL.SelectedValue 为空。 (但是,可以从 FormCollection 中获取所选项目,但这不是重点)。否则,DL 对象仍会正确填充,立即窗口输出如下:

model.DL
{System.Web.Mvc.SelectList}
    base {System.Web.Mvc.MultiSelectList}: {System.Web.Mvc.SelectList}
    SelectedValue: null
model.DL.Items
Count = 2
    [0]: {[1, Item 1]}
    [1]: {[2, Item 2]}
model.DL.SelectedValue
null

Q1:如何改用 SelectedValue 属性?

现在,如果在 Razor 视图中我将 Html SELECT 标记的名称更改为 DL(即与模型中的属性名称相同):

@Html.DropDownList("DL", (SelectList)Model.DL)

我得到一个例外:

No parameterless constructor defined for this object. 
Stack Trace: 
[MissingMethodException: No parameterless constructor defined for this object.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241
System.Activator.CreateInstance(Type type, Boolean nonPublic) +69
System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +199
System.Web.Mvc.DefaultModelBinder.BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult 
...

Q2:为什么?

谢谢。

【问题讨论】:

    标签: asp.net-mvc-3 razor drop-down-menu null selectedvalue


    【解决方案1】:

    MVC 将只返回 POST 中所选选项的值,因此您需要一个属性来包含返回的单个值。

    作为一个好的建议,尝试通过 ViewBag 设置 SelectLists,这有助于让您的 ViewModels 清除需要填充表单的数据。

    所以你的例子可以这样解决:

    public class testCreateModel
    {
        public string s1 { get; set; }
        public int SelectedValue { get; set; }
    }
    

    在你的视图中这样做:

    @Html.DropDownList("SelectedValue", (SelectList)ViewBag.DL)
    

    在您的 GET 操作中填充 ViewBag.DL 之前。

    至于你的 Q2,默认的 ModelBinder 要求所有要绑定的类型都有一个默认的构造函数(以便 ModelBinder 可以创建它们)

    【讨论】:

    • 感谢您使用下拉列表的建议方法。它可以工作,并且拾取所选值所需的工作更少!
    • 谢谢,这是帮助我在 mvc 中使用下拉列表的最佳帖子
    【解决方案2】:

    已选择了一个答案,但看看我是如何做到的。下面是填充下拉列表时我通常如何执行的代码。它非常简单,我建议您以它为基础来构建您的下拉菜单。

    在我的视图顶部,我指定了我的视图模型:

    @model MyProject.ViewModels.MyViewModel
    

    在我看来,我有一个下拉列表,其中显示了用户可以选择的所有银行:

    <table>
         <tr>
              <td><b>Bank:</b></td>
              <td>
                   @Html.DropDownListFor(
                        x => x.BankId,
                        new SelectList(Model.Banks, "Id", "Name", Model.BankId),
                        "-- Select --"
                   )
                   @Html.ValidationMessageFor(x => x.BankId)
              </td>
         </tr>
    </table>
    

    我总是有一个视图的视图模型,我从不将域对象直接传递给视图。在这种情况下,我的视图模型将包含将从数据库中填充的银行列表:

    public class MyViewModel
    {
         // Other properties
    
         public int BankId { get; set; }
         public IEnumerable<Bank> Banks { get; set; }
    }
    

    我的银行域模型:

    public class Bank
    {
         public int Id { get; set; }
         public string Name { get; set; }
    }
    

    然后在我的操作方法中创建我的视图模型的一个实例并从数据库中填充银行列表。完成后,我将视图模型返回到视图:

    public ActionResult MyActionMethod()
    {
         MyViewModel viewModel = new ViewModel
         {
              // Database call to get all the banks
              // GetAll returns a list of Bank objects
              Banks = bankService.GetAll()
         };
    
         return View(viewModel);
    }
    
    [HttpPost]
    public ActionResult MyActionMethod(MyViewModel viewModel)
    {
        // If you have selected an item then BankId would have a value in it
    }
    

    我希望这会有所帮助。

    【讨论】:

    • 非常好,感谢分享。但是,我无法在表单回发中检索数据。有任何想法吗?谢谢
    猜你喜欢
    • 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
    相关资源
    最近更新 更多