在EditorTemplate中DropDownListFor没有选择值

时间:2009-12-16 17:57:09

标签: asp.net-mvc

我有自定义对象的编辑器模板。在该编辑器模板中,我使用了几个DropDownListFor帮助器。在每个中我指定一个唯一的模型属性(带有预先选择的值)和包含所有选择选项的选择列表。

示例:

<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>

我知道正在填充选项值(来自查看源),并且我的模型使用正确的ID值(DocumentCategoryType)传入。

呈现视图时,我的下拉列表中没有选定项目,因此默认为第一个(未选中)值。

有没有人有任何想法?

感谢。

12 个答案:

答案 0 :(得分:28)

我们还通过填充已选择适当SelectList的新SelectListItem解决了该解决方案,但创建了此扩展方法以使对DropDownListFor的调用更加清晰:

public static SelectList MakeSelection(this SelectList list, object selection)
{
    return new SelectList(list.Items, list.DataValueField, list.DataTextField, selection);
}

然后您的DropDownListFor来电变为:

<%= Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList.MakeSelection(Model.DocumentCategoryType)) %>

答案 1 :(得分:18)

查看ASP.NET MVC 2源代码,揭示了此问题的一些解决方案。实质上,在SelectListItem中传递的SelectListSelected属性设置为true的辅助扩展方法中的任何<option>都不会对使用{呈现的selected元素产生任何影响{1}}属性已应用于该项目。

selected元素的<option>属性由

决定

1)检查辅助扩展方法是否传递了SelectList。如果为null,则框架将在ViewData中查找与要为其呈现下拉列表的视图模型属性的键对应的值。如果值为SelectList,则只要模型属性的模型状态为null,这将用于呈现<select>,包括获取任何选定的值。

2)如果在辅助扩展方法中传递了SelectList并且模型属性的模型状态为null,则框架将在ViewData中查找默认值,使用模型属性名称作为键。视图数据中的值将转换为字符串,并且传递给辅助扩展方法的SelectList中的任何项具有一个值(如果未设置任何值,则将检查文本),该值与默认值匹配将Selected属性设置为true,然后使用属性<option>呈现selected="selected"

综合起来,我可以看到有两个合理的选项可以选择一个选项并使用强类型DropDownListFor

使用以下视图模型

public class CategoriesViewModel
{
    public string SelectedCategory { get; private set ; }
    public ICollection<string> Categories { get; private set; }

    public CategoriesViewModel(string selectedCategory, ICollection<string> categories)
    {
        SelectedCategory = selectedCategory;
        Categories = categories;
    }
}

选项1

在控制器的ViewData中设置一个值,使您的视图键入用于呈现下拉列表的集合的属性名称

控制器动作

public class CategoriesController
{
    [HttpGet]
    public ViewResult Select()
    {
        /* some code that gets data from a datasource to populate the view model  */
        ICollection<string> categories = repository.getCategoriesForUser();
        string selectedCategory = repository.getUsersSelectedCategory();

        CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
        this.ViewData["Categories"] = selectedCategory;        

        return View(model);
    }

    [HttpPost]
    public ActionResult Select(CategoriesViewModel model)
    {
        /* some code that does something */
    }
}

并在强类型视图中

<%: Html.DropDownListFor(m => m.Categories, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { @class = "my-css-class" }) %>

选项2

使用所选项目的属性名称

呈现下拉列表

控制器动作

public class CategoriesController
{
    [HttpGet]
    public ViewResult Select()
    {
        /* some code that gets data from a datasource to populate the view model  */
        ICollection<string> categories = repository.getCategoriesForUser();
        string selectedCategory = repository.getUsersSelectedCategory();

        CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);

        return View(model);
    }

    [HttpPost]
    public ActionResult Select(CategoriesViewModel model)
    {
        /* some code that does something */
    }
}

并在强类型视图中

<%: Html.DropDownListFor(m => m.SelectedCategory, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { @class = "my-css-class" }) %>

答案 2 :(得分:14)

确认为@ aspnet.codeplex.com的错误 对于强类型视图,行为只有这样。

解决方法:在视图代码中填充SelectList

<%= Html.DropDown("DocumentCategoryType", new SelectList(Model.Categories,"id","Name",Model.SelectedCategory")) =>

答案 3 :(得分:6)

呸。我最终解决了这个问题。我希望RTM能解决这个问题。

   <%if(Model!=null){ %>
        <%= Html.DropDownListFor(m => m.DocumentCategoryType, new SelectList(Model.DocumentCategoryTypeList,"Value","Text", Model.DocumentCategoryType))%>
        <%}else{%>
            <%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
        <%}%>

答案 4 :(得分:1)

确保在将m.DocumentCategoryType发送到视图时为其分配了值。

通常,当您回发邮件时,此值将重置,因此您只需指定该值即可 回到你的视野时。

创建下拉列表时,您需要传递两个值。 1.这是您存储所选值的地方2.是实际列表

实施例

<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>

我错误地将选择列表项选择值设置为True。这不会做任何事情。而只是在控制器中为m.DocumentCategoryType赋值,这实际上会为您做出选择。

答案 5 :(得分:1)

如果您的下拉列表的源是IEnumerable而不是SelectList,那么这是另一个很好的解决方案:

public static SelectList MakeSelection(this IEnumerable<SelectListItem> list, object selection, string dataValueField = "Value", string dataTextField = "Text")
{
    return new SelectList(list, dataValueField, dataTextField, selection);
}

答案 6 :(得分:0)

Model.DocumentCategoryTypeList

这可能是你的问题。在SelectListItems上,您是否将值设置为.ToString()输出?

 var list = new List<SelectListItem>()
                           {
                               new SelectListItem()
                                   {
                                       Value = Category.Book.ToString(),
                                       Text = "Book"                                     
                                   },
                               new SelectListItem()
                                   {
                                       Value = Category.BitsAndPieces.ToString(),
                                       Text = "Bits And Pieces"                            },
                               new SelectListItem()
                                   {
                                       Value = Category.Envelope.ToString(),
                                       Text = "Envelopes"                              }
                           };

这样做后适合我。它只需要能够匹配对象的值

答案 7 :(得分:0)

我设法解决了同样的问题,说了一下:

new SelectList(sections.Select(s => new { Text = s.SectionName, Value = s.SectionID.ToString() }), "Value", "Text")

这个技巧是将值转换为字符串。我知道在之前的答案中已经提到过,但我发现我的解决方案更清洁:)。希望这会有所帮助。

答案 8 :(得分:0)

从我的项目中复制粘贴:

<%= Html.DropDownListFor(m => m.Profession.Profession_id, new SelectList(Model.Professions, "Profession_id", "Profession_title"),"-- Profession --")%>

传递的模型:

   ...
            public Profession Profession { get; set; }
            public IList<Profession> Professions { get; set; }
    ...

生成的Html:

  <select id="Profession_Profession_id" name="Profession.Profession_id">
    <option value="">-- Profesion --</option>
    <option value="4">Informatico</option>
    <option selected="selected" value="5">Administracion</option>
    </select> 

适合我。我在表单上有这个,唯一的缺点是如果模型无效并且我将模型返回到视图我必须重新加载专业列表。

obj.Professions = ProfileService.GetProfessions();
return View(obj);

答案 9 :(得分:0)

我还遇到了一个字段ProgramName的问题。事实证明我们在BaseController和Layout.cshtml中使用了ViewBag.ProgramName,这是出于不同的目的。由于未在下拉列表中找到ViewBag.ProgramName中的值,因此即使列表中的一个项的SelectListItem.Selected为true,也未选择任何值。我们只是将ViewBag更改为使用不同的密钥,问题就解决了。

答案 10 :(得分:0)

Here is a drop-in DropDownListFor replacement与原始MVC来源略有不同。

示例:

<%=Html.FixedDropDownListFor(m => m.DocumentCategoryType, 
    Model.DocumentCategoryTypeList) %>

答案 11 :(得分:0)

我担心制作如此多的selectList副本的性能,所以相反,我将selectedvalue添加为自定义属性,然后使用jquery实际执行项目选择:

@Html.DropDownListFor(item => item.AttendeeID, attendeeChoices, String.Empty, new { setselectedvalue = Model.AttendeeID })

........


jQuery("select[setselectedvalue]").each(function () { e = jQuery(this); e.val(e.attr("setselectedvalue")); });