我们在DropDownListFor(ASP.NET MVC3版本)中发现了奇怪的行为。它在下拉列表中选择ViewBag属性值而不是Model属性值。
型号:
public class Country {
public string Name { get; set; }
}
public class User {
public Country Country { get; set; }
}
控制器索引操作:
ViewBag.CountryList = new List<Country> { /* Dropdown collection */
new Country() { Name = "Danmark" },
new Country() { Name = "Russia" } };
var user = new User();
user.Country = new Country(){Name = "Russia"}; /* User value */
ViewBag.Country = new Country() { Name = "Danmark" }; /* It affects user */
return View(user);
查看:
@Html.EditorFor(user => user.Country.Name)
@Html.DropDownListFor(user => user.Country.Name,
new SelectList(ViewBag.CountryList, "Name", "Name", Model.Country), "...")
它将显示带有“俄罗斯”值的文本框,并选择“Danmark”值而不是“俄罗斯”。
我没有找到有关此行为的任何文档。这种行为是否正常?为什么这是正常的?因为很难控制ViewBag和Model属性名称。
答案 0 :(得分:5)
我不太确定为什么做出这个决定,但是之所以发生这种情况是因为MVC框架在使用参数提供的值之前尝试使用ViewData提供的值。这就是ViewBag.Country
覆盖参数提供的值Model.Country
的原因。
这就是私有方法SelectInternal
中MVC框架中的written。
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 (!usedViewData) {
if (defaultValue == null) {
defaultValue = htmlHelper.ViewData.Eval(fullName);
}
}
if (defaultValue != null) {
IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture);
HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
List<SelectListItem> newSelectList = new List<SelectListItem>();
foreach (SelectListItem item in selectList) {
item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
newSelectList.Add(item);
}
selectList = newSelectList;
}
此代码defaultValue = htmlHelper.ViewData.Eval(fullName);
尝试从ViewData
获取值,如果它可以获取值,它将使用新列表覆盖提供的参数selectList
。
希望它可以提供帮助。谢谢。
side-node :ViewBag只是ViewData的动态包装类。
答案 1 :(得分:4)
您的操作方法中的以下行是令代码混淆的内容:
ViewBag.Country = new Country() { Name = "Danmark" }; /* It affects user */
那是因为html帮助器会查看几个不同的位置来为生成的控件选取值。在这种情况下,ViewData["Country"]
与ModelState["Country"]
发生冲突,将该属性重命名为其他内容,一切都应该有效。