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调用中手动“使用”列表。 这样做正确地为我设置选定的值。
免责声明:
- 没有用Web表单视图引擎尝试过,但它也应该工作。
- 我没有在v1和v2中testing过这个,但是可能会起作用。