ASP.NET MVC 3中预选的Html.DropDownListFor在Nerd Dinner中无法工作

14

学习下拉列表,我正在尝试添加一个RSVP创建页面,像Scott Gu的博客中所述,在Html.DropDownListFor中列出可用的晚餐。

我可以让下拉列表显示出来,但我无法让其预先选择我想要的值(“Sample Dinner 2”)。我使用一个初始化器在数据库中种了一些晚餐对象。该数据库是使用EF“先代码”方法的sql ce 4.抱歉我知道这是一个常见的问题,不过老实说我已经花了相当长的时间,但还是无法使其工作:

ViewModel

public class RSVPViewModel
{
    public SelectList DinnersList { get; set; }
    public RSVP Rsvp { get; set; }
    public string SelectedItem { get; set; }
}

控制器

    //
    //GET: /RSVP/Create

    public ActionResult Create()
    {
        RSVP rsvp = new RSVP();
        string selected = "Sample Dinner 2";
        var typeList = new SelectList(dbc.Dinners.ToList(), "DinnerID", "Title", selected);

        var viewModel = new RSVPViewModel { DinnersList = typeList, Rsvp = rsvp, SelectedItem = selected };

        return View("Create", viewModel);
    }

视图

@Html.DropDownListFor(model => model.Rsvp.DinnerID, Model.DinnersList)

HTML结果

<select data-val="true" data-val-number="The field DinnerID must be a number." data-val-required="The DinnerID field is required." id="Rsvp_DinnerID" name="Rsvp.DinnerID">
     <option value="1">Sample Dinner 1</option>
     <option value="2">Sample Dinner 2</option>
</select>

所以在页面加载时不会预先选定下拉列表中的"value"为"Sample Dinner 2"的值。当我进行选择并点击提交时,列表显示正常并设置了正确的DinnerID。

也尝试了这个:

@Html.DropDownListFor(x => x.SelectedItem, Model.DinnersList)

这个操作可以从列表中进行预选,但是并没有绑定(或设置)Rsvp.DinnerID。

@Html.DropDownList("DinnersList")

我希望保持mvc3的框架,因此想要使用ViewModel方法来实现强类型(不使用ViewData),最好使用Html.DropDownListFor(而非Html.DropDownList)。在这种情况下,Viewbag似乎是不必要的。

谢谢!

Edit1:

我认为应该使用selectListItems的selectList,因此尝试了这种冗长的方法:

RSVP rsvp = new RSVP();
string selected = "2";
List<SelectListItem> dinners = new List<SelectListItem>();

foreach (Dinner dinner in dbc.Dinners.ToList())
{
    SelectListItem slDinner = new SelectListItem();
    slDinner.Value = dinner.DinnerID.ToString();
    slDinner.Text = dinner.Title;
    slDinner.Selected = (slDinner.Value == selected);
    dinners.Add(slDinner);
 }

 var dinnersList = new SelectList(dinners, "Value", "Text", selected);
 var viewModel = new RSVPViewModel { DinnersList = dinnersList, Rsvp = rsvp, SelectedItem = selected };

然而仍然没有起作用。我应该在 @Html.DropDownListFor 中利用 ViewModel 的 SelectedItem 属性吗?就像这样:

@Html.DropDownListFor(x => x.SelectedItem, Model.DinnersList)

但是我如何获取所选值以设置Rsvp.DinnerID。我认为这被称为绑定。


当您逐步执行代码时,new SelectList(...) 生成的列表中是否有一个其 Selected 属性为 true 的项目? - StriplingWarrior
我不确定你的意思。在selectlist中,我没有使用SelectListItems,所以我看不到Selected Property。另外我在其他地方阅读到(https://dev59.com/MXE95IYBdhLWcg3wN7Kv),大多数情况下Selected property会被忽略(也许@html.dropdownlist("DinnerList")可以工作,但是没有绑定?) - Jay
在下面的答案更改后,我可以看到typeList中有一个名为'SelectedValue'的属性,其值为2且类型为int。 - Jay
5个回答

12

通过阅读这里这里,我终于理解了HtmlDropDownlistFor如何根据你的模型自动选择正确的下拉列表项 - 在RSVP中选择dinnerID(外键到dinner.dinnerID)将导致包含Dinner.DinnerIDs列表的下拉列表预先选择该值。 在SelectList或ViewModel中暂时不需要selectedValue。

解决方案:

    //
    //GET: /RSVP/Create

    public ActionResult Create()
    {
        //automatically preselects matching DinnerID in the Dinner dropdownlist            
        var rsvp = new RSVP {DinnerID = 2 };

        var typeList = new SelectList(dbc.Dinners.ToList(), "DinnerID", "Title");
        var viewModel = new RSVPViewModel { DinnersList = typeList, Rsvp = rsvp};

        return View("Create", viewModel);
    }

请查看我的DDL教程,网址为http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc和http://blogs.msdn.com/b/rickandy/archive/2012/01/09/cascasding-dropdownlist-in-asp-net-mvc.aspx。 - RickAndMSFT

3
您正在使用的SelectList构造函数应该提供所选值,但您提供了所选文本。您可以尝试以下方法:
    int selected = 2;

1
还是没用,仍然默认为列表中的第一个元素。我检查了数据库以确保存在DinnerID=2的晚餐对象。 - Jay

2

Html.DropDownList只能在绑定属性为整型时工作。如果使用其他类型,如枚举类型,它将默认选择第一项。

向模型添加一个包装你想要维护的枚举类型的整型属性:

public myEnumType myProperty {get; set;} // don't bind this to Html.DropDownList

public myEnumType myPropertyAsInt {
    get {return (int)this.myProperty; }
    set {this.myProperty = (myEnumType)value; }
} // bind this instead

不需要在您的SelectList中使用Selected - Html.DropDownList可以很好地同步。

2
这是不正确的。请查看我的DDL教程http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc和http://blogs.msdn.com/b/rickandy/archive/2012/01/09/cascasding-dropdownlist-in-asp-net-mvc.aspx。 - RickAndMSFT
这对我有用,我最初绑定到一个枚举,但是在此示例中将其转换为int链接导致预选项工作。 - Neil

2
请注意,如果有相同名称的查询字符串(QUERY STRING),它将覆盖该行为。不确定是否适用于具有相同名称的隐藏字段(HIDDEN FIELDS)。
例如,DropDownListFor将使用DinnerID的查询字符串值(Query String)(如果找到)。

1

Html.DropDownList接受int属性,DropDownListFor也是如此,但您必须小心您正在做什么。我检查了来自ASP.NET MVC 3的SelectExtensions.cs并发现了以下内容:

当您使用DropDownList(“XyField”,“default”)创建下拉列表时,您必须将选择列表放入ViewBag.XyField中,DropDownList()会正确处理此操作。

当您使用DropDownListFor(m => m.XyField,...)时,您可以显式传递选择列表,例如: DropDownListFor(m => m.XyField,ViewBag.XyFieldList as IEnumerable)

这样做会发生以下情况:

  • DropDownListFor(...)的第二个参数将用作选项的来源
  • 如果有“XyField”的ModelState条目,则将其用作模型值
  • 如果没有模型状态,并且Html.ViewData.Eval(“XyField”)返回不为null,则该值将用作模型值。
  • 如果找到的模型值不为null,则将使用CultureInfo.CurrentCulture将其转换为字符串,并将该值与您的SelectListItem值进行比较以预选列表选项。

注意:如果您将选择列表存储在ViewBag.XyField中,它将在访问模型之前被找到。 不要比较 "selectList.ToString()" 和 "selectList[i].Value" 来预先选择您的选项。将您的选择列表存储在另一个地方!

有趣的是,您可以像从DropDownList()中一样使用带隐式选择列表的DropDownListFor。在这种情况下,甚至会将列表存储在ViewBag.XyField中。要使此功能正常运行,只需将null作为第二个参数调用Helper: DropDownListFor(m=>m.XyField, null)

然后,选择列表将从ViewBag.XyField中提取,并跳过上面列表中的步骤3。因此,如果XyField在模型状态中,则优先于选择列表中自己的Selected属性,否则将使用选择列表“如所”。

祝好 Rolf


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接