【问题标题】:ASP.NET MVC DropDownListFor not selecting value from modelASP.NET MVC DropDownListFor 不从模型中选择值
【发布时间】:2012-06-14 23:18:39
【问题描述】:

我正在使用 ASP.NET MVC 3,但使用DropDownListFor HTML Helper 时遇到了“问题”。

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

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)

RequiredShippingTypeIdInt32 类型)

发生的情况是,RequiredShippingTypeId 的值在下拉列表中没有被选中。

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

He suggests that MVC will lookup the selected value from ViewData, when the select list is from ViewData.我不确定是否是这种情况,因为博客文章已经过时了,而且他在谈论 MVC 1 beta。

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

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

我尽量不在最后RequiredShippingTypeIdToString,这给了我与以前相同的行为:未选择任何项目。

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

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

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

【问题讨论】:

  • 感谢您的解决方法!如此不明显,魔术只适用于“简单”的 lambda 表达式,并且系统不会给出任何警告。

标签: asp.net-mvc-3


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 该死,我不知道。我可以确认确实如此。我尝试使用来自ViewBagShippingTypes,而不是采用一般运输类型的下拉模型:@Html.DropDownListFor(m =&gt; m.Product.RequiredShippingTypeId, ViewBag.ShippingTypes as SelectList)——这很有效。所以,我想我必须坚持使用丑陋的解决方法,可能会为此编写一个 HTML 帮助程序,而不是在我的视图中留下肮脏的 hack。
  • @Darin - 你能指出我的文档吗?谢谢。
  • 如果您使用其他对象/别名从例如获取值,这似乎也适用。 @Html.DropDownListFor(m =&gt; myViewModel.RequiredShippingTypeID, ...。谢谢!
【解决方案2】:

这可能很愚蠢,但是将其添加到您视图中的变量中是否有任何作用?

var shippingTypes = ViewBag.ShippingTypes;

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

【讨论】:

  • 很酷,我只是认为我会建议它作为一种可能的“更清洁”的解决方法。
【解决方案3】:

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

      @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】:

    我刚刚被这个限制击中并想出了一个简单的解决方法。刚刚定义的扩展方法在内部生成 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)
    }
    

    【讨论】:

      【解决方案5】:

      @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本节上面的语法将selected属性添加到从Controller加载的值中

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多