【问题标题】:ViewBag property value in DropDownListFor instead of Model property valueDropDownListFor 中的 ViewBag 属性值而不是 Model 属性值
【发布时间】:2011-07-27 15:51:58
【问题描述】:

我们在 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), "...")

它将显示带有“俄罗斯”值的文本框和选择“丹麦”值而不是“俄罗斯”的下拉菜单。

我没有找到有关此行为的任何文档。这种行为正常吗?为什么是正常的?因为很难控制 ViewBag 和 Model 属性名称。

This sample MVC3 project sources

【问题讨论】:

    标签: asp.net-mvc-3


    【解决方案1】:

    我不太确定为什么会做出这个决定,但这是因为 MVC 框架在使用参数提供的值之前尝试使用 ViewData 提供的值。这就是ViewBag.Country 覆盖参数提供的值Model.Country 的原因。

    这就是在MVC框架中的私有方法SelectInternal中的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 的一个动态包装类。

    【讨论】:

      【解决方案2】:

      您的操作方法中的以下行是混淆代码的原因:

      ViewBag.Country = new Country() { Name = "Danmark" };  /* It affects user */
      

      这是因为 html 帮助程序会查看几个不同的位置以获取生成的控件的值。在这种情况下,ViewData["Country"]ModelState["Country"] 发生冲突,将该属性重命名为其他名称,一切正常。

      【讨论】:

      • 您是否建议始终为 ViewBag 属性名称使用前缀以避免名称冲突?前任。 ViewBag.ViewBag_Country
      • 天哪,你是对的。谢谢你……拯救了我的一天……:)
      猜你喜欢
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多