1

I'm writing a web-app with .NET Core MVC (dotnet version 1.0.4).

I want to pass a Dictionary<string, string> in a ViewData object from controller to view and bind it to <select> element.

This is a result that I want to get:

enter image description here

And I tried two ways to achieve it.

1st way

Controller's code

Dictionary<string, string> animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = new SelectList(animals);

Views's code

<select asp-for="Animal_id" asp-items="(SelectList)@ViewData["animals"]" class="form-control"></select>

That gives me this result

enter image description here

2nd way

Controller's code

Dictionary<string, string> animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = new SelectList(animals.Select(r => new SelectListItem
{
    Text = r.Key,
    Value = r.Value
}));

Views's code

The same.

That gives me this result:

enter image description here

Apparently, something I don't understand about this concept, although I feel like I'm on a right track. Can you please help me - what needs to be done in order to get the result from my first picture (<option>s with values)?

2
  • 1
    You have your images the wrong way around. And its ViewData["animals"] = new SelectList(animals. "Key", "Value"); to generate the correct <option> elements – user3559349 Aug 14 '17 at 21:43
  • @StephenMuecke, wow, I knew that I was missing just a bit. Works like a charm. Please, add this as an answer and I will mark it as a solution. P.S. Pictures order is fine, what is wrong there? – retif Aug 14 '17 at 22:18
4

You using the overload of the SelectList constructor where the parameter is IEnumerable. That overload calls the .ToString() method of each item in your collection, and because they are complex objects, you get the results your seeing. That overload is really only useful if your collection was IEnumerable<string>.

You need to use the overload that accepts arguments for the dataValueField and dataTextField which defines the properties to be used for the options value and display text.

Dictionary<string, string> animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = new SelectList(animals, "Key", "Value");

Note also in your 2nd example, you have already generated an IEnumerable<SelectListItem> To use new SelectList(...) to create an identical IEnumerable<SelectListItem> from the first one is pointless extra ovehead and it can just be

ViewData["animals"] = animals.Select(r => new SelectListItem
{
    Text = r.Key,
    Value = r.Value
}));

and in the view asp-items="(IEnumerable<SelectListItem>)@ViewData["animals"]"

1

With your current code, you are creating a SelectList but not specifying what should be the data value field and data text field (of the collection you are using).

You can use the SelectList overload which takes those 2 params.

ViewData["animals"] = new SelectList(animals.Select(r => new SelectListItem
{
    Value = r.Key.ToString(),
    Text = r.Value
}),"Value","Text");

But that is unnecessary code we are executing. You alreay are creating a list of SelectListItem (to pass to SelectList).You should simply use that collection to build the select element.

var animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = animals.Select(r => new SelectListItem
{
    Value = r.Key.ToString(),
    Text = r.Value
});

And in your view

<select asp-for="SomePropertyName" 
                    asp-items="@(ViewData["animals"] as IEnumerable<SelectListItem>)">

</select>

If you use ViewBag instead of ViewData, You do not need the explicit casting.

ViewBag.AnimalList= animals.Select(r => new SelectListItem
{
    Value = r.Key.ToString(),
    Text = r.Value
});

and

<select asp-for="Name" asp-items="@ViewBag.AnimalList">
</select>
2
  • Yes, that works. Although ViewBag creates a correct <select>, and ViewData "confuses" value and text :) but I got the principle. Thank you. – retif Aug 14 '17 at 22:16
  • 1
    You were setting the Key of dictionary item(the Id value) to the Text of SelectListItem. I have it in the correct form(value=key, text=value(of dictionary item)) – Shyju Aug 15 '17 at 2:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.