SelectListItem中的Selected属性永远不会起作用(DropDownListFor)

时间:2012-03-20 18:13:38

标签: asp.net-mvc asp.net-mvc-3

选择DropDownList的值时遇到问题。我一直在阅读所有相似的帖子,我无法得到解决方案。

实际的方法对我来说似乎非常好,因为我可以检查SelectList中的字段:

var selectList = new List<SelectListItem>(
    from variable in someKindOfCollection
    select new SelectListItem
        {
            Selected = variable.Property == selection,
            Text = variable.Property,
            Value = variable.Property
        });

据说,这给了我完全的控制权。在构建了selectList之后,我可以使用调试器检查变量。一切都很好,其中一个标有“Selected”属性。

然后我使用DropDownListFor来显示视图:

@Html.DropDownListFor(
    g => g.SomePropertyInModel , selectList, new { @class = "cssClass" })

但它不起作用,从不...“渲染”下拉列表,但没有选择任何内容。

非常感谢:)

新示例 首先,我想道歉。我一直在隐藏信息,当然是完全无意的。 所有代码都发生在Razor For Loop中:

@foreach (var loopVariable in Model.Collection)
{
    if (Model.SomeCondition != null)
    {
        selection = someValue;
    }

    var selectList = new List<SelectListItem>(
      from variable in someKindOfCollection
      select new SelectListItem
    {
        Selected = variable.Property == selection,
        Text = variable.Property,
        Value = variable.Property
    });

    @Html.DropDownListFor(
        g => g.SomePropertyInModel , selectList, new { @class = "cssClass" })

}

那么,selectList是导致行为的局部变量吗?对不起,我没想到就是这样。

8 个答案:

答案 0 :(得分:4)

我认为你遇到了同样的问题。我查看了源代码以找到我的解决方案,看起来这对我来说是一个错误。下面的DropDownListFor应该有帮助,关键是你将选中的值传递给html帮助器。希望这会有所帮助。

public static class SelectExtensions {
    public static IHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, object htmlAttributes = null) {
       return DropDownListHelper(helper, ExpressionHelper.GetExpressionText(expression), selectList, selectedValue, optionLabel, htmlAttributes);
    }

    /// <summary>
    /// This is almost identical to the one in ASP.NET MVC 3 however it removes the default values stuff so that the Selected property of the SelectListItem class actually works
    /// </summary>
   private static IHtmlString DropDownListHelper(HtmlHelper helper, string name, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, object htmlAttributes) {
        name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

        // Convert each ListItem to an option tag
        var listItemBuilder = new StringBuilder();

        // Make optionLabel the first item that gets rendered
        if (optionLabel != null)
            listItemBuilder.AppendLine(ListItemToOption(new SelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }, selectedValue));

        // Add the other options
        foreach (var item in selectList) {
            listItemBuilder.AppendLine(ListItemToOption(item, selectedValue));
        }

        // Now add the select tag
        var tag = new TagBuilder("select") { InnerHtml = listItemBuilder.ToString() };
        tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        tag.MergeAttribute("name", name, true);
        tag.GenerateId(name);

        // If there are any errors for a named field, we add the css attribute
        ModelState modelState;

        if (helper.ViewData.ModelState.TryGetValue(name, out modelState)) {
            if (modelState.Errors.Count > 0)
                tag.AddCssClass(HtmlHelper.ValidationInputCssClassName);
        }

        // Add the unobtrusive validation attributes
        tag.MergeAttributes(helper.GetUnobtrusiveValidationAttributes(name));

        return tag.ToHtmlString(TagRenderMode.Normal);
    }

    private static string ListItemToOption(SelectListItem item, string selectedValue) {
        var tag = new TagBuilder("option") { InnerHtml = HttpUtility.HtmlEncode(item.Text) };

        if (item.Value != null)
            tag.Attributes["value"] = item.Value;

        if ((!string.IsNullOrEmpty(selectedValue) && item.Value == selectedValue) || item.Selected)
            tag.Attributes["selected"] = "selected";

        return tag.ToString(TagRenderMode.Normal);
    }
}

答案 1 :(得分:2)

我建议使用视图模型:

public ActionResult Index()
{
    var model = new MyViewModel
    {
        // this will preselect the item with value = "2.400 €" in the collection
        SelectedValue = "2.400 €",

        Values = someKindOfCollection
    };
    return View(model);
}

并在视图中:

@Html.DropDownListFor(
    g => g.SelectedValue, 
    new SelectList(Model.Values, "SomePropertyForValue", "SomePropertyForText"), 
    new { @class = "cssClass" }
)

答案 2 :(得分:2)

您应该再次调试选择列表。

您的所有选项值都没有selected=selected

尝试将列表硬编码为

SelectList = new List<SelectListItem>
        {
            new SelectListItem{Text = "600 €", Value="600 €" , Selected = false},
            new SelectListItem{Text = "1.200 €", Value="1.200 €" , Selected = false},
            new SelectListItem{Text = "2.400 €", Value="2.400 €" , Selected = false},
            new SelectListItem{Text = "3.000 €", Value="3.000 €" , Selected = true},
        };

使用此代码,您的Html.DropDownFor SelectList可以正常工作并生成此HTML

<select id="TheID" name="TheName" class="cssClass">
  <option value="600 €">600 €</option>
  <option value="1.200 €">1.200 €</option>
  <option value="2.400 €">2.400 €</option>
  <option value="3.000 €" selected="selected">3.000 €</option>
</select>

从您的代码中,我无法判断您的比较是否将Selected属性之一设置为true,但这可能是您的代码无效的原因。

答案 3 :(得分:2)

我不知道这会对任何人有所帮助,但这为我解决了......

我的模型中包含了集合和选定的值。

我改变了观点:

@Html.DropDownListFor(
g => g.CollectionName, 
new SelectList(Model.CollectionName, "SomePropertyForValue", "SomePropertyForText", Model.SelectedValue), 
new { @class = "cssClass" }
)

@Html.DropDownListFor(
g => g.SelectedValue, 
new SelectList(Model.CollectionName, "SomePropertyForValue", "SomePropertyForText", Model.SelectedValue), 
new { @class = "cssClass" }
)

当DropDownListFor的第一个参数引用该集合时,我会得到下拉列表,但所选的值永远不会坚持。

答案 4 :(得分:2)

这个问题的解决方案更简单,我们都认为......

当从控制器返回视图时,我们需要做的就是在视图模型上为下拉列表绑定的元素设置属性 - 即:model.SomePropertyInModel =&#39; 5&#39;例如

当我们这样做时

@Html.DropDownListFor(
g => g.SomePropertyInModel , selectList, new { @class = "cssClass" })

HtmlHelper将自动获取要在DropDownList

上显示的默认值

simples!

希望它可以帮助你和所有其他人 - 像我一样! - 为这个明显的问题寻找解决方案已经失去了很多时间。

答案 5 :(得分:1)

我遇到了类似的问题,原因是我没有在我的视图模型上设置由SelectListItems提供的属性值。实际上你根本不需要设置“Selected”属性。要使用原始示例中的措辞,只需将“SomePropertyOnModel”设置为当前选择的任何内容。 DropDownListFor将适当地绑定“Selected”属性。

答案 6 :(得分:0)

我对DropDownListFor的建议是,

  • 将IEnumerable属性传递给传递给View的模型(或viewmodel)。例如:

    private IEnumerable<SelectListItem> GetListItems() 
    {
        var selectList = db.YourDBThings
          .Where(t => t.IsCool == true)
          .Select(x => new SelectListItem
              {
                Value = x.Id.ToString(),
                Text = x.Name
              });
        return new SelectList(issues, "Value", "Text");
    }
    
  • 然后将此IEnumerable添加到您的对象中,假设您的对象中还有一个属性,该属性具有与列表中的“value”之一匹配的ONE项(将被设置为选中的项):

    FancyViewModel myFancyViewModel = new FancyViewModel();
    myFancyViewModel.ListOptions = GetListItems();
    myFancyViewModel.SelectedThingId = 3; //this 3 would match one of the value in the list
    //....
    return View(myFancyViewModel);
    
  • 然后在您收到包含项目列表的FancyViewModel实例的视图中:

    @model Project.ViewModels.FancyViewModel
    @*...*@
    @Html.DropDownListFor(x=>x.SelectedThingId, Model.ListOptions)
    

DropDownListFor中的第一个参数指定包含将在列表中选择的字段的TProperty。第二个是来自模型的列表本身(虽然它可以从任何地方检索!)

答案 7 :(得分:-1)

存在问题,g.SelectedValue必须是模型中的可空类型。