如何使该ASP.NET MVC SelectList正常工作?


126

我在控制器中创建一个selectList,以显示在视图中。

我正在尝试即时创建它,就像这样...

myViewData.PageOptionsDropDown = 
   new SelectList(new [] {"10", "15", "25", "50", "100", "1000"}, "15");

它可以编译,但是输出是错误的...

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
    <option>10</option>
    <option>15</option>
    <option>25</option>
    <option>50</option>
    <option>100</option>
    <option>1000</option>
</select>

请注意如何没有选择任何项目?

我怎样才能解决这个问题??


1
六个答案...一个喜欢的...没有投票:/我给它+1
womp

Answers:


128

这就是我的方法

IList<Customer> customers = repository.GetAll<Customer>();
IEnumerable<SelectListItem> selectList = 
    from c in customers
    select new SelectListItem
    {
        Selected = (c.CustomerID == invoice.CustomerID),
        Text = c.Name,
        Value = c.CustomerID.ToString()
    };

乍一看,我不确定我知道你在追求什么...


2
谢谢你,这帮助我弄清楚了这些东西。
卡多

6
不能解决选定项目的问题,但这是避免选择列表使用魔术字符串的好方法!欢呼声
艾伦·克里斯坦森

11
要解决所选商品的问题,请添加以下代码:当前所选的客户SelectList sList = new SelectList(selectList, "Text", "Value", selected);在哪里selected
jao 2012年

68

我使用扩展方法:

用法

var departmentItems = departments.ToSelectList(d => d.Code + 
                                               " - " + d.Description,
                                               d => d.Id.ToString(),
                                               " - ");

var functionItems = customerFunctions.ToSelectList(f => f.Description, 
                                                   f => f.Id.ToString(), 
                                                   " - ");

public static class MCVExtentions
{
    public static List<SelectListItem> ToSelectList<T>(
        this IEnumerable<T> enumerable, 
        Func<T, string> text, 
        Func<T, string> value, 
        string defaultOption)
    {
        var items = enumerable.Select(f => new SelectListItem()
                                     {
                                         Text = text(f), 
                                         Value = value(f) 
                                     }).ToList();
        items.Insert(0, new SelectListItem()
                    {
                        Text = defaultOption, 
                        Value = "-1" 
                    });
        return items;
    }
}

很好 我添加了一个选定的Func,一个defaultValue选项和第二个重载,没有要指定的任何默认值,这很有效。顺便说一句,如果您要使返回类型为IEnumerable <SelectListItem>,则可以使用yield return语法使此外观看起来很干净
Chris Meek

48

使用接受items, dataValueField, dataTextField, selectedValue作为参数的构造函数:

ViewData["myList"] = 
                new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }
                .Select(x => new {value = x, text = x}), 
                "value", "text", "15");

然后在您看来:

<%=Html.DropDownList("myList") %>

3
好家伙:)我喜欢!我正在尝试执行此操作..但我无法获得.Select(..)部分..不错:)我稍后将在家里进行尝试:)
Pure.Krome

1
Heya Cagdas。效果很好,除了未选择所选字段。任何想法?这是MVC中的错误吗?
Pure.Krome

2
将SelectList项目添加到ViewData对象时(如ViewData [“ myList”] = new SelectList ..),然后使用<%= Html.DropDownList(“ myList”)%>进行呈现,则所选项目起作用。但是,如果不这样做,我将无法使选定的项目起作用。奇怪的。
Çağdaş特勤

@Cagdas -喜再次花花公子..我还没有想通了这一点:(这是怎么一个ViewData的???我有一个强类型的ViewData与它自己的财产... ???
Pure.Krome

@ Pure.Krome-我从问题中的示例中获取了该属性。现在,我正在编辑代码示例。请在几秒钟后查看我的修改。
Çağdaş特勤

19

基于Thomas Stock的答案,我创建了以下重载ToSelectList方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

public static partial class Helpers
{
    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, bool selectAll = false)
    {
        return enumerable.ToSelectList(value, value, selectAll);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, object selectedValue)
    {
        return enumerable.ToSelectList(value, value, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, IEnumerable<object> selectedValues)
    {
        return enumerable.ToSelectList(value, value, selectedValues);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, bool selectAll = false)
    {
        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = selectAll
            };
        }
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, object selectedValue)
    {
        return enumerable.ToSelectList(value, text, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, IEnumerable<object> selectedValues)
    {
        var sel = selectedValues != null
            ? selectedValues.Where(x => x != null).ToList().ConvertAll<string>(x => x.ToString())
            : new List<string>();

        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = sel.Contains(value(f).ToString())
            };
        }
    }
}

在您的控制器中,您可以执行以下操作:

var pageOptions = new[] { "10", "15", "25", "50", "100", "1000" };
ViewBag.PageOptions = pageOptions.ToSelectList(o => o, "15" /*selectedValue*/);

最后在您的视图中,输入:

@Html.DropDownList("PageOptionsDropDown", ViewBag.PageOptions as IEnumerable<SelectListItem>, "(Select one)")

这将产生所需的输出-当然,"(Select one)"如果您不希望第一个空项目,则可以省略上面的optionLabel:

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
<option value="">(Select one)</option>
<option value="10">10</option>
<option selected="selected" value="15">15</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="1000">1000</option>
</select>

更新:可以在此处找到带有XML注释的修订代码清单。


13

问题是,SelectList按设计工作。该错误是在设计中。您可以在SelectedItem中设置Selected属性,但是如果使用GetEnumerator()遍历列表(或者如果Mvc为您执行此操作),则将完全忽略此属性。Mvc将改为创建新的SelectListItems。

您必须将SelectList ctor与SelectListItem [],Text-Name,Value-Name和SelectedValue一起使用。请注意,将要选择的SelectListItem的值(而不是SelectListItem本身)作为SelectedValue传递!例:

SelectList sl = new SelectList( new[]{
  new SelectListItem{ Text="one", Value="1"},
  new SelectListItem{ Text="two", Value="2"},
  new SelectListItem{ Text="three", Value="3"}
}, "Text", "Value", "2" );

(未经测试,但我遇到了同样的问题)

那么第二个选项将获得selected =“ selected”属性。看起来像是很好的旧数据集;-)


11

这是一个选择:

myViewData.PageOptionsDropDown = new[] 
{
 new SelectListItem { Text = "10", Value = "10" },
 new SelectListItem { Text = "15", Value = "15", Selected = true }
 new SelectListItem { Text = "25", Value = "25" },
 new SelectListItem { Text = "50", Value = "50" },
 new SelectListItem { Text = "100", Value = "100" },
 new SelectListItem { Text = "1000", Value = "1000" },
}

所选值的新SelectListItem {Selected = true,Text =“ 15”,Value =“ 15”}。
卡多

哎呀,是的,忘记了包括“选定的”房产,谢谢卡多(Cadoo)=)
murki

10

如果这实际上是您要做的,那么只需将数组声明为字符串即可解决所选项目的问题:

myViewData.PageOptionsDropDown = 
   new SelectList(new string[] {"10", "15", "25", "50", "100", "1000"}, "15");

7

即使您的属性不是简单的对象(如Int,String或Double值),也要使SelectList和SelectedValue一起工作非常简单。

例:

假设我们的Region对象是这样的:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }
}

您的视图模型如下所示:

public class ContactViewModel {
     public DateTime Date { get; set; }
     public Region Region { get; set; }
     public List<Region> Regions { get; set; }
}

您可以使用以下代码:

@Html.DropDownListFor(x => x.Region, new SelectList(Model.Regions, "ID", "Name")) 

仅当您将Region对象的ToString方法重写为类似以下内容时:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }

     public override string ToString()
     {
         return ID.ToString();
     }
}

这有100%保证工作。

但是我真的相信,使SelectList在所有情况下都能100%正常工作的最佳方法是使用Equals方法针对Items集合中的每个项目测试DropDownList或ListBox属性值。


5

看来,如果您具有强类型视图,则需要更改下拉列表的ID,以便它不是继承的类上属性的名称。然后,您需要在您的edit(POST)方法中放入一些逻辑,以从FORMCollection中提取选定的值并将其放在您的实例上,然后再提交更改。

这当然有点奇怪,但是我尝试了一下,并且效果很好。

因此,如果您的班级有一个名为CountryId的字段,并且要显示一个国家名称列表,请使下拉列表具有一个CountryName而不是CountryId的ID,然后在帖子中,您可以使用Collection [“ CountryName”]进行操作。


1
是的,我有同样的问题。只需更改名称即可。谢谢!
davekaro 2010年

4

我有同样的问题。解决方案很简单。只需将传递给DropDownList帮助器的“名称”参数更改为与ViewModel中现有的任何属性都不匹配的内容。在此处阅读更多信息:http : //www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

我引用Dan Watson:

在MVC中,如果对视图进行强类型键入,则将覆盖选择列表的selected选项,并且构造函数上设置的selected option属性将永远不会到达该视图,而是将选择下拉列表中的第一个选项(为什么仍然有些奥秘) 。

干杯!


3

所有这些答案看起来不错,但似乎是控制器正在以众所周知的结构化格式为View准备数据,而不是让视图简单地迭代通过模型传递的IEnumerable <>并构建标准选择列表,然后让DefaultModelBinder通过一个动作参数将选定的商品交付给您。是的,不,为什么不呢?关注点分离,是吗?让控制器构建某些特定于UI和View的东西似乎很奇怪。


3

简单:

string[] someName = new string[] {"10", "15", "25", "50", "100", "1000"};
myViewData.PageOptionsDropDown = new SelectList(someName, "15");

2

我只是这样跑,没有问题,

public class myViewDataObj
    {
        public SelectList PageOptionsDropDown { get; set; }
    }

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

            ViewData["myList"] = myViewData.PageOptionsDropDown;
            return View();
        }

<%=Html.DropDownList("myList") %>

如果您这样做也可以

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" });

            ViewData["myListValues"] = myViewData.PageOptionsDropDown;
            ViewData["myList"] = "15";
            return View();
        }

<%=Html.DropDownList("myList",(IEnumerable<SelectListItem>)ViewData["myListValues"]) %>

1

使用您的示例,这对我有用:

控制器:

ViewData["PageOptionsDropDown"] = new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

视图:

<%= Html.DropDownList("PageOptionsDropDown")%>

是的,这也对我有用。就我而言,该列表是一个实体模型对象。控制器:ViewData [“ Categories”] = new SelectList(db.Categories.ToList(),“ CategoryId”,“ CategoryName”,“ 15”); 视图:Html.DropDownList(“ CategoryId”,(SelectList)ViewData [“ Categories”],“ --select--”)
Junior Mayh

1
MonthRepository monthRepository = new MonthRepository();
IQueryable<MonthEntity> entities = monthRepository.GetAllMonth();
List<MonthEntity> monthEntities = new List<MonthEntity>();

foreach(var r in entities)
{
    monthEntities.Add(r);
}

ViewData["Month"] = new SelectList(monthEntities, "MonthID", "Month", "Mars");

1

我这样做是这样的:

List<SelectListItem> list = new List<SelectListItem>{
new SelectListItem {Selected = true, Text = "Select", Value = "0"},
new SelectListItem {Selected = true, Text = "1", Value = "1"},
new SelectListItem {Selected = true, Text = "2", Value = "2"}
};
return list.ToArray();

ToArray()解决了这些问题。


1

如果要将一些随机文本传递到DropDownList,例如--Select--,可以使用以下代码轻松完成此操作:

@Html.DropDownListFor(x => x.CategoryId, new SelectList(Model.Categories, "Id", "Name"), "--Select--", new { @class = "form-control" })


0

在模型中选择的值将代替默认项被利用。(我同意我没有阅读所有帖子)


0

我不记得如何设置mvc 1,但似乎它也希望选择列表的名称也与它所属的字段相同...

我发现,就像上面提到的那样,当我发送的ViewData命名为与字段相同时,我的选择列表在mvc2中不起作用。

例如:

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForName"]) %>

工作时间

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForID"]) %>

无效,因为ViewData名称“ ForID”与其工作的字段的名称相同


0

可能的解释是您要绑定的selectlist值不是字符串。

因此,在该示例中,参数'PageOptionsDropDown'是模型中的字符串吗?因为如果不是,那么将不会显示列表中的选定值。


0

如果您在Html.DropDownList扩展方法中查找MVC 2的源代码,则它永远不会检查SelectList类SelectedValue属性。它只会尝试与您的模型匹配。

以上所有都是关于主题的变体,即如何将一堆数据发送到视图以创建下拉列表,并且它们彼此一样好(或多或少)。

问题出在视图中。创建自己的DropDownList扩展方法(该方法确实会尊重您设置的selectvalue),或者手动进行迭代。哪个最适合您。


@Franz Antesberger说的差不多。
西蒙·哈尔西

0

如果您的模型中有一个集合,并且您的View是强类型的,则可以对此进行一些修改:

@Html.DropDownListFor(x => x.RegionID, 
    new SelectList(Model.Regions,"RegionID", "RegionName", Model.RegionID))

-要么-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
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.