ASP.NET MVC DropDownList不从模型中选择值

时间:2012-06-14 23:18:39

标签: asp.net-mvc-3

我正在使用ASP.NET MVC 3,并且使用DropDownListFor HTML帮助程序遇到了“陷阱”。

我在我的控制器中执行此操作:

ViewBag.ShippingTypes = this.SelectListDataRepository.GetShippingTypes();

GetShippingTypes方法:

public SelectList GetShippingTypes()
{
    List<ShippingTypeDto> shippingTypes = this._orderService.GetShippingTypes();

    return new SelectList(shippingTypes, "Id", "Name");
}

我把它放在ViewBag而不是模型中(我为每个视图都有强类型模型)的原因是我有一组使用EditorTemplate呈现的项目,它们也需要访问ShippingTypes选择列表。

否则我需要遍历整个集合,然后分配一个ShippingTypes属性。

到目前为止一切顺利。

在我看来,我这样做:

@Html.DropDownListFor(m => m.RequiredShippingTypeId, ViewBag.ShippingTypes as SelectList)

RequiredShippingTypeId属于Int32

在下拉列表中,RequiredShippingTypeId的值,会发生什么。

我遇到了这个:http://web.archive.org/web/20090628135923/http://blog.benhartonline.com/post/2008/11/24/ASPNET-MVC-SelectList-selectedValue-Gotcha.aspx

他建议当选择列表来自ViewData时,MVC将从ViewData中查找所选值。我不确定是不是这样了,因为博客文章已经过时了,他正在讨论MVC 1 beta。

解决此问题的解决方法是:

@Html.DropDownListFor(m => m.RequiredShippingTypeId, new SelectList(ViewBag.ShippingTypes as IEnumerable<SelectListItem>, "Value", "Text", Model.RequiredShippingTypeId.ToString()))

我最后在ToString上尝试不RequiredShippingTypeId,这给了我与以前相同的行为:没有选择任何项目。

我认为这是一个数据类型问题。最终,HTML帮助器将字符串(在选择列表中)与Int32(来自RequiredShippingTypeId)进行比较。

但是当将SelectList放在ViewBag中时,为什么它在将它添加到模型时完美地工作,并在视图中执行此操作时不起作用:

@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, Model.ShippingTypes)

5 个答案:

答案 0 :(得分:30)

这不起作用的原因是因为DropDownListFor助手的限制:它能够使用作为第一个参数传递的lambda表达式来推断所选值这个lambda表达式是一个简单的属性访问表达式。例如,由于编辑器模板,这不适用于数组索引器访问表达式。

你基本上拥有(不包括编辑器模板):

@Html.DropDownListFor(
    m => m.ShippingTypes[i].RequiredShippingTypeId, 
    ViewBag.ShippingTypes as IEnumerable<SelectListItem>
)

不支持以下内容:m => m.ShippingTypes[i].RequiredShippingTypeId。它仅适用于简单的属性访问表达式,但不适用于索引集合访问。

通过在构建SelectList时显式传递选定的值,您找到的解决方法是解决此问题的正确方法。

答案 1 :(得分:0)

这可能很愚蠢,但是在视图中将它添加到变量中会做什么吗?

var shippingTypes = ViewBag.ShippingTypes;

@Html.DropDownListFor(m => m.Product.RequiredShippingTypeId, shippingTypes)

答案 2 :(得分:0)

@ html.DropdownList有一个重载方法来处理这个问题。 可以在HTML下拉列表中设置所选值。

@Html.DropDownListFor(m => m.Section[b].State, 
              new SelectList(Model.StatesDropdown, "value", "text", Model.Section[b].State))

我能够从模型中获取所选值。

"value", "text", Model.Section[b].State此部分上面的语法将所选属性添加到从Controller

加载的值中

答案 3 :(得分:0)

您可以为复杂类型的每个下拉列表字段创建动态viewdata而不是viewbag。  希望这会给你提示如何做到这一点

      @if (Model.Exchange != null)
                                {
                                    for (int i = 0; i < Model.Exchange.Count; i++)
                                    {
                                        <tr>
                                            @Html.HiddenFor(model => model.Exchange[i].companyExchangeDtlsId)
                                            <td>
                                                 
                                                @Html.DropDownListFor(model => model.Exchange[i].categoryDetailsId, ViewData["Exchange" + i] as SelectList, " Select category", new { @id = "ddlexchange", @class = "form-control custom-form-control required" })
                                                @Html.ValidationMessageFor(model => model.Exchange[i].categoryDetailsId, "", new { @class = "text-danger" })
                                            </td>
                                            <td>
                                                @Html.TextAreaFor(model => model.Exchange[i].Address, new { @class = "form-control custom-form-control", @style = "margin:5px;display:inline" })
                                            
                                                @Html.ValidationMessageFor(model => model.Exchange[i].Address, "", new { @class = "text-danger" })
                                            </td>
                                        </tr>
                                    }

                                }

  ViewModel CompanyDetail = companyDetailService.GetCompanyDetails(id);
               if (CompanyDetail.Exchange != null)
                for (int i = 0; i < CompanyDetail.Exchange.Count; i++)
                {
                    ViewData["Exchange" + i]= new SelectList(companyDetailService.GetComapnyExchange(), "categoryDetailsId", "LOV", CompanyDetail.Exchange[i].categoryDetailsId);
                }

答案 4 :(得分:0)

我受到了这个限制,并想出了一个简单的解决方法。刚刚定义的扩展方法,内部生成SelectList正确的选定项目。

public static class HtmlHelperExtensions
{
    public static MvcHtmlString DropDownListForEx<TModel, TProperty>(
       this HtmlHelper<TModel> htmlHelper,
       Expression<Func<TModel, TProperty>> expression,
       IEnumerable<SelectListItem> selectList,
       object htmlAttributes = null)
    {
        var selectedValue = expression.Compile().Invoke(htmlHelper.ViewData.Model);
        var selectListCopy = new SelectList(selectList.ToList(), nameof(SelectListItem.Value), nameof(SelectListItem.Text), selectedValue);

        return htmlHelper.DropDownListFor(expression, selectListCopy, htmlAttributes);
    }
}

最好的是,此扩展程序的使用方式与原始DropDownListFor相同:

@for(var i = 0; i < Model.Items.Count(); i++)
{
   @Html.DropDownListForEx(x => x.Items[i].CountryId, Model.AllCountries)
}