Cannot convert type 'System.Collections.Generic.List<string>' to 'System.Web.Mvc.SelectList'
Asked Answered
R

5

21

I have the following Action method, which have a viewBag with a list of strings:-

public ActionResult Login(string returnUrl)
        {
            List<string> domains = new List<string>();
    domains.Add("DomainA");

            ViewBag.ReturnUrl = returnUrl;
            ViewBag.Domains = domains;
            return View();
        }

and on the view i am trying to build a drop-down list that shows the viewBag strings as follow:-

@Html.DropDownList("domains",(SelectList)ViewBag.domains )

But i got the following error :-

Cannot convert type 'System.Collections.Generic.List' to 'System.Web.Mvc.SelectList'

So can anyone adive why i can not populate my DropDown list of a list of stings ? Thanks

Rowlett answered 30/1, 2014 at 17:56 Comment(0)
C
33

Because DropDownList does not accept a list of strings. It accepts IEnumerable<SelectListItem>. It's your responsibility to convert your list of strings into that. This is easy enough though:

domains.Select(m => new SelectListItem { Text = m, Value = m })

Then, you can feed that to DropDownList:

@Html.DropDownList("domains", ((List<string>)ViewBag.domains).Select(m => new SelectListItem { Text = m, Value = m }))
Cartesian answered 30/1, 2014 at 18:0 Comment(3)
Still get 'Cannot convert type 'System.Web.Mvc.SelectListItem[]' to 'System.Collections.Generic.List<string>''Valley
@vapcguy: The code here assumes ViewBag.domains is a List<string> because it is in the OP's question. It sounds like in your case, the ViewBag member is already an IEnumerable<SelectListItem> so you should cast to that instead.Cartesian
Yeah, I had to back out that entire cast when I went to the view portion: @Html.DropDownList("agency_id", (IEnumerable<SelectListItem>)ViewData["agency_id"]) was how mine looked, in the end. I was feeding it this: var agencies = db.AGENCIES.OrderBy(e => e.FULLNAME).ToList(); var agenciesList = agencies.Select(d => new SelectListItem { Text = d.FULLNAME, Value = d.AGENCY_ID.ToString() }); ViewData["agency_id"] = agenciesList;Valley
T
5

To complete Chris Pratt's answer, here's some sample code to create the dropdown :

@Html.DropDownList("domains", new SelectList(((List<string>)ViewBag.domains).Select(d => new SelectListItem { Text = d, Value = d }), "Value", "Text"))

Which will produce the following markup :

<select id="domains" name="domains">
    <option value="item 1">item 1</option>
    <option value="item 2">item 2</option>
    <option value="item 3">item 3</option>
</select>
Tedmund answered 30/1, 2014 at 18:11 Comment(2)
You don't need to create an instance of SelectList. All DropDownList requires is IEnumerable<SelectListItem>.Cartesian
List<string> does not contain a defintion for Select and no extension method Select accepting a first argument of type List<string> could be found. My app is MVC 5, maybe something has changed since this post? I'm not sure how to reference assemblies from the view page, could that be my problem?Spiegelman
T
4

ViewBag is not strongly typed. You can use ViewModel classes to pass instances to view so that view can utilize more than one data source.

    public ActionResult Login(string returnUrl)
    {
        List<string> domains = new List<string>();
        domains.Add("DomainA");

        ViewModel model=new ViewModel();
        model.ReturnUrl = returnUrl;
        model.Domains =new SelectList(domains);
        return View(model);
    }

    Public Class ViewModel()
    {
        property Url ReturnUrl{get;set;}
        property SelectList Domains{get;set;}
    }
Tambourine answered 30/1, 2014 at 20:44 Comment(0)
S
0
@Html.DropDownListFor(
     m => m.Country, 
          new SelectList(_CountryList, "CountryID", "Title"),
          new { @class = "form-control" }
)
Sexagenarian answered 29/8, 2016 at 21:0 Comment(1)
Need code for filling _CountryList for this to be an applicable example. Code only answers, unless obvious, are discouraged.Valley
V
0

You really need to have a "key", or index, for each value, because you have to convert each name to an IEnumerable<SelectListItem>, which requires an ID value and a Text string to display. You could do that using one of two ways:

Use a Dictionary

Make a Dictionary<int, string>:

Dictionary<int, string> domainDict = new Dictionary<int, string>();

and everytime you add a domain, you add a number:

domainDict.Add(1, "DomainA");

If you have a source list for this information with multiple domains, you could do a foreach on that list and use an indexer variable similar to what I show, below, instead of manually adding the items.

You will need a model. Create a class called DomainViewModel.cs and add this inside:

public class DomainViewModel()
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Then iterate over your dictionary to add the items to a DomainViewModel, and then add each of those items to a List<DomainViewModel>, similar to what I have below in the next section, except it would look like this:

List<DomainViewModel> lstDomainModel = new List<DomainViewModel>();

foreach(KeyValuePair<int, string> kvp in domainDict)
{
    DomainViewModel d = new DomainViewModel();
    d.Id = kvp.Key;  // number 
    d.Name = kvp.Value;  // domain name
    lstDomainModel.Add(d);
}

(Skip to Finishing Up, below)

List iteration with loop indexer

If you don't want to use a Dictionary<>, you could just add the index on the fly by iterating the List<string> and putting it into a List<DomainViewModel> directly. Here's how you would do that:

1) Ensure you have created the DomainViewModel.cs class from above.

2) Edit your controller function to build your List<string>, then iterate over it to add it in chunks of DomainViewModel to a new List<DomainViewModel> using an indexer variable (idx):

List<string> domains = new List<string>();
domains.Add("DomainA");  // etc.

List<DomainViewModel> lstDomainModel = new List<lstDomainModel>();
int idx = 0;

// Add your List<string> to your List<DomainViewModel>
foreach (string s in domainList)
{
    DomainViewModel domainModel = new DomainViewModel();
    domainModel.Id = idx;
    domainModel.Name = s;
    lstDomainModel.Add(domainModel);
    idx++;
}

Finishing Up

Using either method, once you have it in a List<DomainViewModel>, you could do:

IEnumerable<SimpleListItem> domainList = 
    lstDomainModel.Select(d => new SelectListItem { 
            Text = d.Name, 
            Value = d.Id.ToString() 
        }
    );
ViewBag.Domains = domainList;

And show it in your view like this:

@Html.DropDownList("Domains", (IEnumerable<SelectListItem>)ViewBag.Domains)
Valley answered 9/10, 2018 at 18:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.