ASP.NET MVC Html.DropDownList SelectedValue

我试过这是RC1,然后升级到RC2,这并没有解决问题。

// in my controller ViewData["UserId"] = new SelectList( users, "UserId", "DisplayName", selectedUserId.Value); // this has a value 

结果:SelectedValue属性在对象上设置

 // in my view <%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%> 

结果:所有预期的选项都呈现给客户端,但未选定属性。 SelectedValue中的项目存在于列表中,但是列表中的第一个项目总是默认选中。

我应该怎么做?

更新感谢John Feminella的回复,我发现问题是什么。 “UserId”是强制types为“我的视图”的模型中的一个属性。 当Html.DropDownList(“UserId”更改为除“UserId”以外的任何其他名称时,所选值正确呈现。

这导致值不被绑定到模型。

这是我解决这个问题的方法:

我有以下几点:

控制器:

 ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ; 

视图

 <%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%> 

改变如下:

视图

 <%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%> 

看起来,DropDown不能有相同的名称有ViewData名称:S很奇怪,但它的工作。

尝试这个:

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

接着:

 var list = new[] { new Person { Id = 1, Name = "Name1" }, new Person { Id = 2, Name = "Name2" }, new Person { Id = 3, Name = "Name3" } }; var selectList = new SelectList(list, "Id", "Name", 2); ViewData["People"] = selectList; Html.DropDownList("PeopleClass", (SelectList)ViewData["People"]) 

使用MVC RC2,我得到:

 <select id="PeopleClass" name="PeopleClass"> <option value="1">Name1</option> <option selected="selected" value="2">Name2</option> <option value="3">Name3</option> </select> 

您仍然可以将DropDown命名为“UserId”,并且仍然有模型绑定为您正确工作。

这个工作的唯一要求是,包含SelectList的ViewData键不具有与要绑定的Model属性相同的名称。 在你的具体情况下,这将是:

 // in my controller ViewData["Users"] = new SelectList( users, "UserId", "DisplayName", selectedUserId.Value); // this has a value // in my view <%=Html.DropDownList("UserId", (SelectList)ViewData["Users"])%> 

这将生成一个名为UserId的select元素,它与您的模型中的UserId属性名称相同,因此模型联编程序将使用在由Html.DropDownList助手生成的html select元素中select的值来设置它。

我不知道为什么特定的Html.DropDownList构造函数不会selectSelectList中指定的值,当您将select列表放在ViewData中的关键字等于属性名称。 我怀疑它与在其他场景中如何使用DropDownList帮助器有关,其中约定是在ViewData中有一个与您的模型中的属性名称相同的SelectList。 这将正确工作:

 // in my controller ViewData["UserId"] = new SelectList( users, "UserId", "DisplayName", selectedUserId.Value); // this has a value // in my view <%=Html.DropDownList("UserId")%> 

如果我们不认为这是一个错误,团队应该修复,至lessMSDN应该改善文档。 令人困惑的确是来自这个糟糕的文件。 在MSDN中 ,它解释了参数名称

 Type: System.String The name of the form field to return. 

这只是意味着它生成的最终html将使用该参数作为selectinput的名称。 但是,它实际上意味着更多。

我猜devise师假定用户将使用视图模型来显示下拉列表,也将使用回发到相同的视图模型。 但在很多情况下,我们并没有真正遵循这个假设。

使用上面的例子,

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

如果我们遵循这个假设,我们应该为这个下拉列表相关视图定义一个视图模型

 public class PersonsSelectViewModel{ public string SelectedPersonId, public List<SelectListItem> Persons; } 

因为回发时,只有选定的值会回发,所以它假定它应该回到模型的属性SelectedPersonId,这意味着Html.DropDownList的第一个参数名称应该是“SelectedPersonId”。 所以,devise者认为当在视图中显示模型视图时,模型的SelectedPersonId属性应该保持该下拉列表的默认值。 甚至认为你的List <SelectListItem> Persons已经设置了Selected标志来指明哪一个被select/默认,tml.DropDownList实际上会忽略它,并重build它自己的IEnumerable <SelectListItem>,并根据名称设置默认/select的项目。

这里是来自asp.net mvc的代码

 private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes) { ... bool usedViewData = false; // If we got a null selectList, try to use ViewData to get the list of items. if (selectList == null) { selectList = htmlHelper.GetSelectData(name); usedViewData = true; } object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); // If we haven't already used ViewData to get the entire list of items then we need to // use the ViewData-supplied value before using the parameter-supplied value. if (defaultValue == null && !String.IsNullOrEmpty(name)) { if (!usedViewData) { defaultValue = htmlHelper.ViewData.Eval(name); } else if (metadata != null) { defaultValue = metadata.Model; } } if (defaultValue != null) { selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple); } ... return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal); } 

所以,代码实际上更进一步,它不仅试图在模型中查找名称,而且在viewdata中查找名称,只要它find一个,它将重buildselectList并忽略您的原始select。

问题是,在很多情况下,我们并没有真正使用它。 我们只是想抛出一个/多个项目select列表select设置为true。

当然,解决scheme很简单,使用不在模型中,也不在视图数据中的名称。 当找不到匹配时,将使用原始的selectList,原始的Selected将生效。

但我仍然认为mvc应该通过增加一个条件来改善它

 if ((defaultValue != null) && (!selectList.Any(i=>i.Selected))) { selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple); } 

因为,如果原来的selectList已经有一个Selected,为什么你会忽略它呢?

只是我的想法。

在以前的MVC 3中的代码不起作用,但这是一个好的开始。 我会修好它。 我已经testing了这个代码,它在MVC 3 Razor C#中工作此代码使用ViewModel模式来填充返回List<SelectListItem>的属性。

Model类

 public class Product { public string Name { get; set; } public decimal Price { get; set; } } 

ViewModel类

 using System.Web.Mvc; public class ProductListviewModel { public List<SelectListItem> Products { get; set; } } 

控制器方法

 public ViewResult List() { var productList = new List<SelectListItem>(); foreach (Product p in Products) { productList.Add(new SelectListItem { Value = p.ProductId.ToString(), Text = "Product: " + p.Name + " " + p.Price.ToString(), // To set the selected item use the following code // Note: you should not set every item to selected Selected = true }); } ProductListViewModel productListVM = new ProductListViewModeld(); productListVM.Products = productList; return View(productListVM); } 

风景

 @model MvcApp.ViewModels.ProductListViewModel @using (Html.BeginForm()) { @Html.DropDownList("Products", Model.Products) } 

HTML输出将是类似的东西

 <select id="Products" name="Products"> <option value="3">Product: Widget 10.00</option> <option value="4">Product: Gadget 5.95</option> </select> 

取决于你如何格式化输出。 我希望这有帮助。 代码确实有效。

这似乎是SelectExtensions类中的一个错误,因为它只会检查ViewData,而不是所选项目的模型。 所以诀窍就是将选定的项目从模型复制到属性名称下的ViewData集合中。

这是从我给MVC论坛的答案采取的,我也有一个更完整的答案在博客文章 ,使用卡的DropDownList属性 …

给定一个模型

 public class ArticleType { public Guid Id { get; set; } public string Description { get; set; } } public class Article { public Guid Id { get; set; } public string Name { get; set; } public ArticleType { get; set; } } 

和一个基本的观点模型

 public class ArticleModel { public Guid Id { get; set; } public string Name { get; set; } [UIHint("DropDownList")] public Guid ArticleType { get; set; } } 

然后我们编写如下的DropDownList编辑器模板。

 <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <script runat="server"> IEnumerable<SelectListItem> GetSelectList() { var metaData = ViewData.ModelMetadata; if (metaData == null) { return null; } var selected = Model is SelectListItem ? ((SelectListItem) Model).Value : Model.ToString(); ViewData[metaData.PropertyName] = selected; var key = metaData.PropertyName + "List"; return (IEnumerable<SelectListItem>)ViewData[key]; } </script> <%= Html.DropDownList(null, GetSelectList()) %> 

如果您将视图模型中的ArticleType更改为SelectListItem,这也将起作用,但您必须按照Kazi的博客实现types转换器,并注册它以强制活页夹将其视为简单types。

在你的控制器中,我们有…

 public ArticleController { ... public ActionResult Edit(int id) { var entity = repository.FindOne<Article>(id); var model = builder.Convert<ArticleModel>(entity); var types = repository.FindAll<ArticleTypes>(); ViewData["ArticleTypeList"] = builder.Convert<SelectListItem>(types); return VIew(model); } ... } 

问题在于,Dropbox不能像列表框一样工作,至less是ASP.NET MVC2devise期望的方式:Dropbox只允许零个或一个值,因为列表框可以有多个值select。 所以,严格的HTML,该值不应该在选项列表中作为“select”标志,而是在input本身。

看下面的例子:

 <select id="combo" name="combo" value="id2"> <option value="id1">This is option 1</option> <option value="id2" selected="selected">This is option 2</option> <option value="id3">This is option 3</option> </select> <select id="listbox" name="listbox" multiple> <option value="id1">This is option 1</option> <option value="id2" selected="selected">This is option 2</option> <option value="id3">This is option 3</option> </select> 

组合有选项,但也有它的值属性设置 。 所以,如果你想让ASP.NET MVC2渲染一个Dropbox,并且还有一个特定的值(即默认值等),你应该在渲染中给它一个值,如下所示:

 // in my view <%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%> 

在ASP.NET MVC 3中,您可以简单地将您的列表添加到ViewData …

 var options = new List<SelectListItem>(); options.Add(new SelectListItem { Value = "1", Text = "1" }); options.Add(new SelectListItem { Value = "2", Text = "2" }); options.Add(new SelectListItem { Value = "3", Text = "3", Selected = true }); ViewData["options"] = options; 

…然后在剃刀视图中按名称引用…

 @Html.DropDownList("options") 

您不必在DropDownList调用中手动“使用”列表。 这样做正确地为我设置选定的值。

免责声明:

  1. 没有用Web表单视图引擎尝试过,但它也应该工作。
  2. 我没有在v1和v2中testing过这个,但是可能会起作用。