How can I get this ASP.NET MVC SelectList to work?

C#asp.net MvcSelectlist

C# Problem Overview


I create a selectList in my controller, to display in the view.

I'm trying to create it on the fly, sorta thing .. like this...

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

It compiles, but the output is bad...

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

Notice how no item is selected?

How can I fix this??

C# Solutions


Solution 1 - C#

This is how I do it

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

At second glance I'm not sure I know what you are after...

Solution 2 - C#

I use an extension method:

usage

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

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

with

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

Solution 3 - C#

Using the constructor that accepts items, dataValueField, dataTextField, selectedValue as parameters :

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

Then in your view :

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

Solution 4 - C#

Building off Thomas Stock's answer, I created these overloaded ToSelectList methods:

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

In your controller, you might do the following:

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

And finally in your View, put:

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

It will result in the desired output--of course, you can leave out the "(Select one)" optionLabel above if you don't want the first empty item:

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

Update: A revised code listing can be found here with XML comments.

Solution 5 - C#

The problem is, SelectList works as designed. The bug is in the design. You may set the Selected Property in SelectedItem, but this will completely be ignored, if you traverse the list with the GetEnumerator() (or if Mvc does that for you). Mvc will create new SelectListItems instead.

You have to use the SelectList ctor with the SelectListItem[], the Text-Name, the Value-Name and the SelectedValue. Be aware to pass as SelectedValue the VALUE of SelectListItem, which you want to be selected, not the SelectListItem itself! Example:

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

(not tested this, but I had the same problem)

then the 2nd option will get the selected="selected" attribute. That looks like good old DataSets ;-)

Solution 6 - C#

This is an option:

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" },
}

Solution 7 - C#

If that's literally all you want to do then just declaring the array as string fixes the selected item problem:

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

Solution 8 - C#

It's very simple to get SelectList and SelectedValue working together, even if your property isn't a simple object like a Int, String or a Double value.

Example:

Assuming our Region object is something like this:

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

And your view model is something like:

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

You can have the code below:

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

Only if you override the ToString method of Region object to something like:

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

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

This have 100% garantee to work.

But I really believe the best way to get SelectList 100% working in all circustances is by using the Equals method to test DropDownList or ListBox property value against each item on items collection.

Solution 9 - C#

It seems if you have a strongly typed view you need to change the ID of the dropdown so that it is NOT the name of a property on the inherrited class. You then need to put some logic in your edit (POST) method to pull off the selected value from the FORMCollection and put it on to your instance before committing your changes.

This is certainly a little strange, but i tried it and it works.

So if you class has a field called CountryId say, and you're displaying a list of country names, make the dropdown have an id of CountryName rather than CountryId, then in the post, you can do something with Collection["CountryName"].

Solution 10 - C#

I had the exact same problem. The solution is simple. Just change the "name" parameter passed to the DropDownList helper to something that does not match any of the properties existing in your ViewModel. read more here: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

I quote the Dan Watson:

> In MVC if the view is strongly typed the selectlist’s selected option will be overridden and the selected option property set on the constructor will never reach the view and the first option in the dropdown will be selected instead (why is still a bit of a mystery).

cheers!

Solution 11 - C#

All these answers look great, but seems to be that the controller is preparing data for a View in a well-known structured format vs. letting the view simply iterate an IEnumerable<> delivered via the model and build a standard select list then let DefaultModelBinder deliver the selected item back to you via an action parameter. Yes, no, why not? Separation of concerns, yes? Seems odd to have the controller to build something so UI and View specific.

Solution 12 - C#

Simple:

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

Solution 13 - C#

I just ran it like this and had no problems,

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

and

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

it also worked if you do this,

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

and

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

Solution 14 - C#

Using your example this worked for me:

controller:

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

view:

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

Solution 15 - C#

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

Solution 16 - C#

I do it like this:

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

The ToArray() takes care of the problems.

Solution 17 - C#

If you want to pass some random text to your DropDownList, for example --Select-- you can easy do this using this code:

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

Solution 18 - C#

It may be the case that you have some ambiguity in your ViewData:

Take a look Here

Solution 19 - C#

the value selected in the model takes advantage instead of the default item. (I agree I didn't read all posts)

Solution 20 - C#

I can't remember how mvc 1 was setup, but it seems that it wanted the select list named the same as the field it belonged too...

What I found, as someone kind of said above, is that my select lists weren't working in mvc2 when the ViewData they were sent as was named the same as the field.

For example:

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

works when

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

does not work as the ViewData name "ForID" is named the same as the field it is working for

Solution 21 - C#

A possible explanation is that the selectlist value that you are binding to is not a string.

So in that example, is the parameter 'PageOptionsDropDown' a string in your model? Because if it isn't then the selected value in the list wouldn't be shown.

Solution 22 - C#

If you look in the source code for MVC 2 at the Html.DropDownList extension method, it never checks the SelectList class SelectedValue property. It will only ever try to match against your Model.

All the above are all variations on a theme, ie how do you send a bunch of data to the view to for a drop-down list & they're all as good as each other (more-or-less).

The problem is in the view. Either create your own DropDownList extension method that does respect the selectvalue you set, or iterate though by hand. Which ever works best for you.

Solution 23 - C#

If you have a collection in your model and your View is strongly type, some variation of this will work:

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

-or-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPure.KromeView Question on Stackoverflow
Solution 1 - C#mhenrixonView Answer on Stackoverflow
Solution 2 - C#Thomas StockView Answer on Stackoverflow
Solution 3 - C#Çağdaş TekinView Answer on Stackoverflow
Solution 4 - C#JustinStolleView Answer on Stackoverflow
Solution 5 - C#Franz AntesbergerView Answer on Stackoverflow
Solution 6 - C#murkiView Answer on Stackoverflow
Solution 7 - C#Matt CottonView Answer on Stackoverflow
Solution 8 - C#ararogView Answer on Stackoverflow
Solution 9 - C#AdamView Answer on Stackoverflow
Solution 10 - C#cleftherisView Answer on Stackoverflow
Solution 11 - C#user514005View Answer on Stackoverflow
Solution 12 - C#MunkView Answer on Stackoverflow
Solution 13 - C#Tony BorfView Answer on Stackoverflow
Solution 14 - C#CadooView Answer on Stackoverflow
Solution 15 - C#CactusView Answer on Stackoverflow
Solution 16 - C#femseksView Answer on Stackoverflow
Solution 17 - C#MünichView Answer on Stackoverflow
Solution 18 - C#KP.View Answer on Stackoverflow
Solution 19 - C#DanielView Answer on Stackoverflow
Solution 20 - C#MarkView Answer on Stackoverflow
Solution 21 - C#FruitDealerView Answer on Stackoverflow
Solution 22 - C#Simon HalseyView Answer on Stackoverflow
Solution 23 - C#MarkView Answer on Stackoverflow