ASP.NET MVC Html.DropDownList SelectedValue


103

我尝试过这是RC1,然后升级到RC2,但仍无法解决问题。

// in my controller
ViewData["UserId"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

结果:在对象上设置了SelectedValue属性

// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%>

结果:所有期望的选项都呈现给客户端,但是未设置selected属性。SelectedValue中的项目存在于列表中,但列表中的第一项始终默认为选中状态。

我应该怎么做?

更新 感谢John Feminella的答复,我发现了问题所在。“ UserId”是我的视图强烈键入的模型中的一个属性。当Html.DropDownList(“ UserId”更改为除“ UserId”以外的任何其他名称时,所选值将正确呈现。

但是,这导致该值未绑定到模型。


您确定该值在列表中吗?
约翰·希恩

这个问题仍然在ASP.NET MVC的第1版存在
马蒂亚斯˚F

什么是selectedUserId !?
fulvio 2010年

如果您输入的名称与您的属性不同,那么您如何绑定更新时的值?
ryudice 2011年

Answers:


68

这就是我解决此问题的方法:

我有以下内容:

控制器:

ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ;

视图

<%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%>

由以下更改:

视图

<%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%>

看起来DropDown的名称不能与ViewData名称:S很奇怪,但是可以正常工作。


19
+1代表“ DropDown不得具有相同的名称,且具有ViewData名称”大感谢
Daniel Dyson 2010年

谢谢!!!在经过许多小时的思考之后,您才解决了我的问题:)
Jen

1
这适用于选定的值,但是当您尝试更新db中的“ DealerTypes”时会出现问题,因为DropDownList现在已绑定到模型中不存在的“ DealerTypesDD”。一种解决方法是将一个隐藏字段和htmlAttributes添加到DropDownList:<input type =“ hidden” name =“ DealerTypes” id =“ DealerTypes” value =“” /> <%= Html.DropDownList(“ DealerTypesDD”,ViewData [ “ DealerTypes”]作为SelectList,新建{@onchange =“ DealerTypes.value = this.value”})%>
Zim 2011年

3
您最好在
视图

1
我勒个去!这在MVC5中不固定???@Paul Hatcher提到的另一个技巧是,将选定的ID复制到ViewData [“ DealerTypes”]。
jsgoupil 2014年

51

试试这个:

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

然后:

var list = new[] {   
    new Person { Id = 1, Name = "Name1" }, 
    new Person { Id = 2, Name = "Name2" }, 
    new Person { Id = 3, Name = "Name3" } 
};

var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["People"] = selectList;

Html.DropDownList("PeopleClass", (SelectList)ViewData["People"])

使用MVC RC2,我得到:

<select id="PeopleClass" name="PeopleClass">
    <option value="1">Name1</option>
    <option selected="selected" value="2">Name2</option>
    <option value="3">Name3</option>
</select>

这有助于查明原因。我已经更新了我的问题,以反映增加的内容。
blu

是模型的第一名?控制器第二?第三点很清楚,但是第2点.. ???
rr 2012年

好的答案,但是使用ViewModel更好吗?
Jess

@Jess:我在5年前的2009年3月写了这个答案。时代变了!随时更新。:)
John Feminella 2014年

5

您仍然可以将DropDown命名为“ UserId”,并且模型绑定仍然可以正常工作。

起作用的唯一要求是,包含SelectList的ViewData密钥与要绑定的Model属性的名称不同。在您的特定情况下,这将是:

// in my controller
ViewData["Users"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["Users"])%>

这将产生一个名为UserId的select元素,该元素与模型中的UserId属性具有相同的名称,因此,模型绑定程序将使用在由Html.DropDownList帮助器生成的html的select元素中选择的值来设置它。

我不确定为什么当您将选择列表放入与属性名称相等的键的ViewData中时,为什么特定的Html.DropDownList构造函数不会选择SelectList中指定的值。我怀疑这与在其他情况下如何使用DropDownList帮助程序有关,在这种情况下,惯例是您在ViewData中确实有一个SelectList,其名称与模型中的属性相同。这将正常工作:

// in my controller
ViewData["UserId"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

// in my view
<%=Html.DropDownList("UserId")%>

非常感谢很多同伴,最重要的是,这对我
有用

最后!经过数小时的尝试,我终于找到了您的“唯一要求”。做到了。
SteveCav

2

如果我们认为这不是团队应解决的错误,则MSDN应该至少对文档进行改进。令人困惑的是,这确实来自糟糕的文件。在MSDN中,它将参数名称解释 为,

Type: System.String
The name of the form field to return.

这只是意味着它生成的最终html将使用该参数作为选择输入的名称。但是,实际上,这还意味着更多。

我猜设计师假设用户将使用视图模型来显示下拉列表,还将使用回发到相同的视图模型。但是在很多情况下,我们实际上并不遵循这个假设。

使用上面的例子,

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

如果遵循假设,则应该为此下拉列表相关视图定义视图模型

public class PersonsSelectViewModel{
    public string SelectedPersonId,
    public List<SelectListItem> Persons;
}

因为在回发时,只有选定的值才会回发,因此假定它应回发到模型的属性SelectedPersonId,这意味着Html.DropDownList的第一个参数名称应为“ SelectedPersonId”。因此,设计人员认为,在视图中显示模型视图时,模型的属性SelectedPersonId应该包含该下拉列表的默认值。即使您的List <SelectListItem>人员已经设置了Selected标志来指示已选择/默认,tml.DropDownList实际上将忽略它并重建它自己的IEnumerable <SelectListItem>并根据名称设置默认/选中的项。

这是来自asp.net mvc的代码

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
            string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
            IDictionary<string, object> htmlAttributes)
{
    ...

    bool usedViewData = false;

    // If we got a null selectList, try to use ViewData to get the list of items.
    if (selectList == null)
    {
        selectList = htmlHelper.GetSelectData(name);
        usedViewData = true;
    }

    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 (defaultValue == null && !String.IsNullOrEmpty(name))
    {
        if (!usedViewData)
        {
            defaultValue = htmlHelper.ViewData.Eval(name);
        }
        else if (metadata != null)
        {
            defaultValue = metadata.Model;
        }
    }

    if (defaultValue != null)
    {
        selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
    }

    ...

    return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}

因此,代码实际上走得更远,它不仅尝试在模型中查找名称,而且还在视图数据中查找名称,一旦找到名称,它将重新构建selectList并忽略原始的Selected。

问题是,在很多情况下,我们并不是真的那样使用它。我们只想抛出一个selectList,其中select / selected项设置为true。

当然,解决方案很简单,使用不在模型或视图数据中的名称。当找不到匹配项时,它将使用原始的selectList,并且原始的Selected将生效。

但是我仍然认为mvc应该通过增加一个条件来改善它

if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
    selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}

因为,如果原始的selectList已经有一个Selected,那么为什么要忽略它呢?

只是我的想法。


到目前为止,这确实是我读过的最好的解释。救了我很多头。我要做的就是设置viewmodel属性的值,并且它起作用了。谢谢。
Moses Machua '16

2

MVC 3以前的文章中的代码不起作用,但这是一个好的开始。我会修好它。我已经测试了此代码,并且可以在MVC 3 Razor C#中工作。此代码使用ViewModel模式填充返回的属性List<SelectListItem>

模型类

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

ViewModel类

using System.Web.Mvc;

public class ProductListviewModel
{
    public List<SelectListItem> Products { get; set; }
}

控制器方法

public ViewResult List()
{
    var productList = new List<SelectListItem>();

    foreach (Product p in Products)
    {
        productList.Add(new SelectListItem
        {
            Value = p.ProductId.ToString(),
            Text = "Product: " + p.Name + " " + p.Price.ToString(),
            // To set the selected item use the following code 
            // Note: you should not set every item to selected
            Selected = true
        });
    }

    ProductListViewModel productListVM = new ProductListViewModeld();

    productListVM.Products = productList;

    return View(productListVM);
}

风景

@model MvcApp.ViewModels.ProductListViewModel

@using (Html.BeginForm())
{
    @Html.DropDownList("Products", Model.Products)
}

HTML输出将类似于

<select id="Products" name="Products">
    <option value="3">Product: Widget 10.00</option>
    <option value="4">Product: Gadget 5.95</option>
</select>

取决于您格式化输出的方式。我希望这有帮助。该代码确实有效。


1
这不会设置selected选项。
杰西

为了使用SelectListItem设置所选项目,请将Selected属性设置为true。
wayne.blackmon 2014年

1

这似乎是SelectExtensions类中的错误,因为它只会检查ViewData而不是所选项目的模型。因此,诀窍是将所选项目从模型中复制到属性名称下的ViewData集合中。

这取自我在MVC论坛上给出的答案,在使用Kazi的DropDownList属性博客文章中,我也有一个更完整的答案...

给定一个模型

public class ArticleType
{
   public Guid Id { get; set; }
   public string Description { get; set; }
}

public class Article
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public ArticleType { get; set; }
}

和一个基本的视图模型

public class ArticleModel
{
     public Guid Id { get; set; }
     public string Name { get; set; }

     [UIHint("DropDownList")]
     public Guid ArticleType { get; set; }
}

然后,我们编写一个DropDownList编辑器模板,如下所示。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">  
    IEnumerable<SelectListItem> GetSelectList()
    {
        var metaData = ViewData.ModelMetadata;
        if (metaData == null)
        {
            return null;
        }

        var selected = Model is SelectListItem ? ((SelectListItem) Model).Value : Model.ToString();
        ViewData[metaData.PropertyName] = selected;

        var key = metaData.PropertyName + "List";
        return (IEnumerable<SelectListItem>)ViewData[key];
    }
</script>
<%= Html.DropDownList(null, GetSelectList()) %>

如果将视图模型中的ArticleType更改为SelectListItem,这也将起作用,尽管您确实必须按照Kazi的博客实现类型转换器并将其注册,以强制活页夹将其视为简单类型。

在您的控制器中,我们可以...

public ArticleController 
{
     ...
     public ActionResult Edit(int id)
     {
          var entity = repository.FindOne<Article>(id);
          var model = builder.Convert<ArticleModel>(entity);

          var types = repository.FindAll<ArticleTypes>();
          ViewData["ArticleTypeList"] = builder.Convert<SelectListItem>(types);

          return VIew(model);
     }
     ...
}

感谢您的答复,我将不得不检查一下。
蓝光

0

问题在于Dropbox不能与列表框一样工作,至少是ASP.NET MVC2设计所期望的方式:Dropbox仅允许零或一个值,因为Listbox可以具有多个值选择。因此,严格限制HTML,该值不应在选项列表中作为“ selected”标志,而应在输入本身中。

请参见以下示例:

<select id="combo" name="combo" value="id2">
  <option value="id1">This is option 1</option>
  <option value="id2" selected="selected">This is option 2</option>
  <option value="id3">This is option 3</option>
</select>

<select id="listbox" name="listbox" multiple>
  <option value="id1">This is option 1</option>
  <option value="id2" selected="selected">This is option 2</option>
  <option value="id3">This is option 3</option>
</select>

组合框已选择选项,但其value属性也已设置。因此,如果您希望ASP.NET MVC2呈现一个保管箱并且还选择了一个特定值(例如,默认值等),则应在呈现中为其赋予一个值,如下所示:

// in my view             
<%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%>

0

在ASP.NET MVC 3中,您可以简单地将列表添加到ViewData ...

var options = new List<SelectListItem>();

options.Add(new SelectListItem { Value = "1", Text = "1" });
options.Add(new SelectListItem { Value = "2", Text = "2" });
options.Add(new SelectListItem { Value = "3", Text = "3", Selected = true });

ViewData["options"] = options;

...然后在剃须刀视图中按名称引用...

@Html.DropDownList("options")

您无需在DropDownList调用中手动“使用”列表。这样也可以为我正确设置选定的值。

免责声明:

  1. 尚未使用Web窗体视图引擎尝试过此操作,但它也应该起作用。
  2. 我尚未在v1和v2中对此进行测试,但它可能有效。

0

我设法获得了预期的结果,但是方法略有不同。在下拉列表中,我使用了模型,然后引用了它。不确定这是否是您想要的。

@Html.DropDownList("Example", new SelectList(Model.FeeStructures, "Id", "NameOfFeeStructure", Model.Matters.FeeStructures))

上面的Model.Matters.FeeStructures是我的ID,可以是您应选择的项目的值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.