asp.net-mvc ASP.NET MVC Html.DropDownList SelectedValue

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/624828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:24:22  来源:igfitidea点击:

ASP.NET MVC Html.DropDownList SelectedValue

asp.net-mvc

提问by blu

I have tried this is RC1 and then upgraded to RC2 which did not resolve the issue.

我试过这是 RC1,然后升级到 RC2 没有解决问题。

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

result: the SelectedValue property is set on the object

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

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

result: all expected options are rendered to the client, but the selected attribute is not set. The item in SelectedValue exists within the list, but the first item in the list is always defaulted to selected.

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

How should I be doing this?

我该怎么做?

UpdateThanks to John Feminella's reply I found out what the issue is. "UserId" is a property in the Model my View is strongly typed to. When Html.DropDownList("UserId" is changed to any other name but "UserId", the selected value is rendered correctly.

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

This results in the value not being bound to the model though.

不过,这会导致该值未绑定到模型。

回答by Sanchitos

This is how I fixed this problem:

这是我解决这个问题的方法:

I had the following:

我有以下几点:

Controller:

控制器:

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

View

看法

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

Changed by the following:

通过以下更改:

View

看法

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

It appears that the DropDown must not have the same name has the ViewData name :S weird but it worked.

看起来 DropDown 不能具有相同的名称,但它的 ViewData 名称很奇怪:S 很奇怪,但它有效。

回答by John Feminella

Try this:

尝试这个:

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

And then:

进而:

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"])

With MVC RC2, I get:

使用 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>

回答by Rui

You can still name the DropDown as "UserId" and still have model binding working correctly for you.

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

The only requirement for this to work is that the ViewData key that contains the SelectList does not have the same name as the Model property that you want to bind. In your specific case this would be:

使其工作的唯一要求是包含 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"])%>

This will produce a select element that is named UserId, which has the same name as the UserId property in your model and therefore the model binder will set it with the value selected in the html's select element generated by the Html.DropDownList helper.

这将生成一个名为 UserId 的选择元素,它与模型中的 UserId 属性同名,因此模型绑定器将使用 Html.DropDownList 助手生成的 html 选择元素中选择的值设置它。

I'm not sure why that particular Html.DropDownList constructor won't select the value specified in the SelectList when you put the select list in the ViewData with a key equal to the property name. I suspect it has something to do with how the DropDownList helper is used in other scenarios, where the convention is that you do have a SelectList in the ViewData with the same name as the property in your model. This will work correctly:

我不确定当您将选择列表放入 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")%>

回答by liuhongbo

If we don't think this is a bug the team should fix, at lease MSDN should improve the document. The confusing really comes from the poor document of this. In MSDN, it explains the parameters nameas,

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

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

This just means the final html it generates will use that parameter as the name of the select input. But, it actually means more than that.

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

I guess the designer assumes that user will use a view model to display the dropdownlist, also will use post back to the sameview model. But in a lot cases, we don't really follow that assumption.

我猜设计者假设用户将使用视图模型来显示下拉列表,也会使用回发到相同的视图模型。但在很多情况下,我们并没有真正遵循这个假设。

Use the example above,

使用上面的例子,

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

If we follow the assumption,we should define a view model for this dropdownlist related view

如果我们遵循假设,我们应该为这个下拉列表相关视图定义一个视图模型

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

Because when post back, only the selected value will post back, so it assume it should post back to the model's property SelectedPersonId, which means Html.DropDownList's first parameter nameshould be 'SelectedPersonId'. So, the designer thinks that when display the model view in the view, the model's property SelectedPersonId should hold the default value of that dropdown list. Even thought your List<SelectListItem> Persons already set the Selected flag to indicate which one is selected/default, the tml.DropDownList will actually ignore that and rebuild it's own IEnumerable<SelectListItem> and set the default/selected item based on the name.

因为回发时,只有选中的值会回发,所以假设应该回发到模型的属性SelectedPersonId,也就是说Html.DropDownList的第一个参数应该是'SelectedPersonId'。因此,设计者认为在视图中显示模型视图时,模型的属性 SelectedPersonId 应该保留该下拉列表的默认值。即使你的 List<SelectListItem> Persons 已经设置了 Selected 标志来指示哪个被选中/默认,tml.DropDownList 实际上会忽略它并重建它自己的 IEnumerable<SelectListItem> 并根据名称设置默认/选定项目。

Here is the code from asp.net mvc

这是来自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);
}

So, the code actually went further, it not only try to look up the name in the model, but also in the viewdata, as soon as it finds one, it will rebuild the selectList and ignore your original Selected.

所以,代码实际上更进一步,它不仅尝试在模型中查找名称,还尝试在视图数据中查找名称,一旦找到,它就会重建 selectList 并忽略您原来的 Selected。

The problem is, in a lot of cases, we don't really use it that way. we just want to throw in a selectList with one/multiple item(s) Selected set true.

问题是,在很多情况下,我们并没有真正那样使用它。我们只想抛出一个 selectList,其中一个/多个项目 Selected 设置为 true。

Of course the solution is simple, use a name that not in the model nor in the viewdata. When it can not find a match, it will use the original selectList and the original Selected will take affect.

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

But i still think mvc should improve it by add one more condition

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

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

Because, if the original selectList has already had one Selected, why would you ignore that?

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

Just my thoughts.

只是我的想法。

回答by wayne.blackmon

The code in the previous MVC 3 post does not work but it is a good start. I will fix it. I have tested this code and it works in MVC 3 Razor C# This code uses the ViewModel pattern to populate a property that returns a List<SelectListItem>.

之前 MVC 3 帖子中的代码不起作用,但这是一个好的开始。我会修好它。我已经测试了这段代码,它在 MVC 3 Razor C# 中工作。这段代码使用 ViewModel 模式来填充一个返回List<SelectListItem>.

The Model class

模型类

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

The ViewModel class

视图模型类

using System.Web.Mvc;

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

The Controller Method

控制器方法

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);
}

The view

风景

@model MvcApp.ViewModels.ProductListViewModel

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

The HTML output will be something like

HTML 输出将类似于

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

depending on how you format the output. I hope this helps. The code does work.

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

回答by Paul Hatcher

This appears to be a bug in the SelectExtensions class as it will only check the ViewData rather than the model for the selected item. So the trick is to copy the selected item from the model into the ViewData collection under the name of the property.

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

This is taken from the answer I gave on the MVC forums, I also have a more complete answer in a blog postthat uses Kazi's DropDownList attribute...

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

Given a model

给定一个模型

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; }
}

and a basic view model of

和一个基本的视图模型

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

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

Then we write a DropDownList editor template as follows..

然后我们写一个 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()) %>

This will also work if you change ArticleType in the view model to a SelectListItem, though you do have to implement a type converter as per Kazi's blog and register it to force the binder to treat this as a simple type.

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

In your controller we then have...

在您的控制器中,我们有...

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);
     }
     ...
}

回答by dalotodo

The problems is that dropboxes don't work the same as listboxes, at least the way ASP.NET MVC2 design expects: A dropbox allows only zero or one values, as listboxes can have a multiple value selection. So, being strict with HTML, that value shouldn't be in the option list as "selected" flag, but in the input itself.

问题是 Dropbox 与列表框的工作方式不同,至少 ASP.NET MVC2 设计所期望的方式是:一个 dropbox 只允许零或一个值,因为列表框可以有多个值选择。因此,严格遵守 HTML,该值不应作为“已选择”标志出现在选项列表中,而应出现在输入本身中。

See the following example:

请参阅以下示例:

<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>

The combo has the option selected, but also has its value attribute set. So, if you want ASP.NET MVC2 to render a dropbox and also have a specific value selected (i.e., default values, etc.), you should give it a value in the rendering, like this:

该组合选择了选项,但也设置了其 value 属性。所以,如果你想让 ASP.NET MVC2 渲染一个 dropbox 并且还选择了一个特定的值(即默认值等),你应该在渲染中给它一个值,像这样:

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

回答by John Bubriski

In ASP.NET MVC 3 you can simply add your list to ViewData...

在 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;

...and then reference it by name in your razor view...

...然后在您的剃刀视图中按名称引用它...

@Html.DropDownList("options")

You don't have to manually "use" the list in the DropDownList call. Doing it this way correctly set the selected value for me too.

您不必在 DropDownList 调用中手动“使用”列表。这样做也正确地为我设置了选定的值。

Disclaimer:

免责声明:

  1. Haven't tried this with the web forms view engine, but it should work too.
  2. I haven't tested this in the v1 and v2, but it might work.
  1. 还没有用 Web 表单视图引擎尝试过这个,但它也应该可以工作。
  2. 我没有在 v1 和 v2 中测试过这个,但它可能有效。

回答by Jukes

I managed to get the desired result, but with a slightly different approach. In the Dropdownlist i used the Model and then referenced it. Not sure if this was what you were looking for.

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

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

Model.Matters.FeeStructures in above is my id, which could be your value of the item that should be selected.

上面的 Model.Matters.FeeStructures 是我的 id,这可能是您应该选择的项目的值。