简体   繁体   中英

Generic Function using TModel to Convert to IEnumerable<SelectListItem>

I found this article that shows how to convert a List into an IEnumerable. Could someone explain to me if it is possible to convert that into a Generic function that could be used by many lists?

For instance, I have a

public class City
{
    public int CityId { get; set; }
    public string CityName { get; set; }
}
public class State 
{
    public int StateId { get; set; }
    public string StateName { get; set; }
    public string StateAbbreviation { get; set; }
}

Then I have these 2 lists where I want to display a dropdown:

List<City> cities
List<State> states

I could set up 2 different methods that do something similar to this, but then I have to copy/paste this code around to multiple lists, which is not what I want.

public static IEnumerable<SelectListItem> GetCitiesSelectList()
{
    IEnumerable<SelectListItem> cityList = GetCities().Select(x => new SelectListItem() { Text = x.CityName, Value = x.CityId.ToString() });
    return qList;
}

What I'm wondering is if there is something similar to this, but be able to pass in any type of list and also pass in the lists' Text and Value? I know you can do something with TModel , but I don't fully understand it and was hoping someone could push me in the right direction.

What about this:

var cities = new SelectList(cityList, "CityId", "CityName");
var states = new SelectList(cityList, "StateId", "StateAbbreviation");

SelectList is casteable to IEnumerable<SelectListItem> .

Any generic method you write won't be much simpler than just using a Linq Select :

var cityList = cities.Select(c => new SelectListItem
{
    Name = c.CityName,
    Value = c.CityId.ToString()
});

But if you really want to make it generic, you could do this:

public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> input,
    Func<T, string> valueFunc,
    Func<T, string> nameFunc)
{
    return input.Select(i => new SelectListItem
    {
        Value = valueFunc(i),
        Name = nameFunc(i)
    });
}

And use like this:

var cityList = cities.ToSelectList(c => c.CityId.ToString(), c => c.CityName);

Naming your model consistently would be the easiest way. Say you have separate entity for drop down like { Id , Name} and use that common model for drop down conversion. public class DropDown {

    public IEnumerable<int> SelectedItems
    {
        get;
        set;
    }


    public IEnumerable<SelectListItem> Items
    {
        get;
        set;
    }


    public IEnumerable<string> SelectedItemsString
    {
        get;
        set;
    }
}

irrespective of how many list items you want to convert into drop down pass the list to the helper method which does the conversion using the drop down Entity and returns back what u expect !!

IEnumerable<SelectListItem> dropdownItems = new MultiSelectList(YourEntity, "ID", "Name", selectedId);
            DropDown fboDropDown = new DropDown { Items = dropdownItems, SelectedItems = selectedId };

Can be used for Drop down as well as multi Select List

Create a base class SelectListItem .

public class SelectListItem
{
    public virtual string Text { get; set; }
    public virtual string Value { get; set; }
}

public class City : SelectListItem
{
    public int CityId { get; set; }
    public string CityName { get; set; }
    public override string Text
    {
        get { return CityName; }
        set { CityName = value; }
    }
    public override string Value
    {
        get { return CityId.ToString(); }
        set { CityId = (int)value; }
    }
}
public class State : SelectListItem
{
    public int StateId { get; set; }
    public string StateName { get; set; }
    public string StateAbbreviation { get; set; }
    public override string Text
    {
        get { return StateName; }
        set { StateName = value; }
    }
    public override string Value
    {
        get { return StateId.ToString(); }
        set { StateId = (int)value; }
    }
}

@miguelerm's answer is solid. However, if you're uncomfortable using string constants for properties, you can create an extension method for this conversion:

public static class EnumerableExtensions
{
    public static IEnumerable<SelectListItem> ToSelectList<T>(
       this IEnumerable<T> collection,
       Func<T, object> textSelector,
       Func<T, object> valueSelector)
    {
        // null checking omitted for brevity
        foreach (var item in collection)
        {
            yield return new SelectListItem()
            {
                Text = textSelector(item) as string,
                Value = valueSelector(item) as string
            };
        }
    }
}

You can use it in Razor like so:

@Html.DropDownListFor(m => m.SelectedCity, Model.Cities.ToSelectList(c => c.CityName, city => c.CityId))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM