I am trying to create a drop down list but it gives me an error saying 'Cannot implicitly convert type 'string' to 'System.Web.Mvc.SelectList'. My code is below:
Application Database Model:
public string dropdown{ get; set; }
Application View Model:
public SelectList dropdown{ get; set; }
ApplicationService.cs:
public static SelectList GetDropdownList(string currSelection)
{
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Value = "1", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "2", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "3", Text = "All of the Above" });
return new SelectList(list, "Value", "Text", currSelection);
}
in my controller i am calling:
applicationviewmodel.dropdown= ApplicationService.GetDropdownList(null);
and then trying to save it in database as:
ApplicationDatabaseModel.dropdown= applicationviewmodel.dropdown;
This is where i get this error.
In my view i have:
#Html.DropDownListFor(x => x.dropdown, applicationviewmodel.dropdown)
I am not sure how to make this work.
I find it's easier to just have a List as part of your model and use a simple linq statement. Simple example below for a countries drop down:
assuming you have a model like
public class MyModel()
{
public int CountryId { get; set; }
public List<Country> Countries { get; set; }
}
and a Country class of
public class Country()
{
public int Id { get; set; }
public string Name { get; set; }
}
in your view you can then do the following:
#Html.DropDownListFor(m => m.CountryId,
Model.Countries.Select(x =>
new SelectListItem { Text = x.Name, Value = x.Id.ToString(), Selected = Model.CountryId == x.Id }, "Please Select...", null)
This:
#Html.DropDownListFor(x => x.dropdown, applicationviewmodel.dropdown)
..is incorrect. It is trying to store the selected item into the SelectList instance.
What you want is a string variable on the view model that this value is selected into:
public class ApplicationViewModel {
public SelectList DropDown { get; set; }
public string SelectedDropDownValue { get; set; }
// .. the rest of the properties here
}
Then your view becomes this:
#Html.DropDownListFor(x => x.SelectedDropDownValue, Model.DropDown)
This says "store the selected value into SelectedDropDownValue".
Then, you need to change how you build your SelectList. Value is what gets posted to your property.. Text is what is displayed in the browser.
So this:
list.Add(new SelectListItem { Value = "1", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "2", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "3", Text = "All of the Above" });
..has to be this:
list.Add(new SelectListItem { Value = "firstvalue", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "secondvalue", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "all of the above", Text = "All of the Above" });
..because they are strings (unless of course, you want the numbers to be posted back).
Then, finally, your controller code becomes this:
// assign the string value to the string property
ApplicationDatabaseModel.dropdown = applicationviewmodel.SelectedDropDownValue;
Related
I have this MultipleSelectList in my view:
#Html.ListBoxFor(s => s.Id,
new MultiSelectList((IEnumerable<SelectListItem>)ViewData["ddlList"], "Value", "Text", Model.Id),
new { #style = "margin-top:250px", multiple = "multiple" })
This list is populated here
#{
using (var b = new Entity())
{
ViewData["ddlList"] = b.Table.Select(e => new SelectListItem()
{
Value = e.Id.ToString(),
Text = e.Name
}).ToList();
}
}
This is my model
public string Name { get; set; }
public int[] Id { get; set; }
The problem is that when I select multiple options, only the first one gets to my controller like this:
int[] value = modelObj.Id;
modelObj.Id;--stores my selected values
Someone knows how can I solve this?
Selected values will be array of string not array of int. So, change the type of Id property to type of string[]:
public string[] Id { get; set; }
I'm trying to do this:
This is my ViewModel and Model:
public class OpeningYearViewModel
{
public int OpeningYearId { get; set; }
public string Description { get; set; }
public List<Grade> GradesList { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string Name { get; set; }
public int CurrencyId { get; set; }
public int Cost { get; set; }
}
This is my Controller. I build a SelecList here and pass it to the view through the ViewBag
OpeningYearViewModel viewmodel = new OpeningYearViewModel {
OpeningYearId = 1,
Description = "2015 - II",
GradesList = new List<Grade>
{
new Grade { GradeId = 1, Name = "Grade 1", CurrencyId = 1, Cost = 100 },
new Grade { GradeId = 2, Name = "Grade 2", CurrencyId = 2, Cost = 200 },
new Grade { GradeId = 3, Name = "Grade 3", CurrencyId = 2, Cost = 150 }
}
};
SelectList list = new SelectList(
new List<SelectListItem>
{
new SelectListItem { Text = "S/.", Value = "1"},
new SelectListItem { Text = "$", Value = "2"},
}, "Value" , "Text");
ViewBag.currencyList = list;
return View(viewmodel);
And in my View I need a DropDownListFor for every item on GradesList so I do this:
#model Test.Models.OpeningYearViewModel
#for(int i = 0; i < Model.GradesList.Count; i++)
{
#Html.DropDownListFor(x => x.GradesList[i].CurrencyId, new SelectList(ViewBag.currencyList, "Value", "Text"))
#Model.GradesList[i].CurrencyId //This is just to know the CurrencyId on every item.
}
I'm getting every select correctly rendered, but I can't get the correct option selected on the page load:
render of view
It is possible to do what I'm trying to do and I'm doing something wrong, or DropDownListFor works in a different way?
Thanks!
I can't understand why this is happening but you can workaround it by setting explicitly the selected value. This can be done by passing Model.GradesList[i].CurrencyId as fourth parameter to the SelectList's constructor:
#for(int i = 0; i < Model.GradesList.Count; i++)
{
#Html.DropDownListFor(x => x.GradesList[i].CurrencyId,
new SelectList(ViewBag.currencyList, "Value", "Text", Model.GradesList[i].CurrencyId))
}
Since, the DropDownListFor is used in loop to generate indexed inputs; so generate input controls will be generated with name as "GradeList[0].CurrencyId", "GradeList[1].CurrencyId"......Due to this framework will not bind the selected value in Select List as it is unable to get the value in reflection for selection. That's why you have to use the following SelectList constructor to set the selected value.
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
However, if your DropDownListFor is bind to a simple expression like
#Html.DropDownListFor(model => model.CurrencyId, new SelectList(ViewBag.Items, "Value", "Text"))
then selection will work automatically.
I got two ways to bind my list of values to a dropdown in MVC3. But not sure which is the difference and the best/simpler way to bind.
//Code
public List<SelectListItem> CountryList
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Bangladesh" },
new SelectListItem { Value = "2", Text = "India" },
new SelectListItem { Value = "3", Text = "Nepal" },
new SelectListItem { Value = "4", Text = "SriLanka" },
};
}
}
(Or)
public SelectList StatusList()
{
List<SelectListItem> lstStatus = new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Yes" },
new SelectListItem { Value = "2", Text = "No" },
};
return new SelectList(lstStatus, "Value", "Text", Status);
}
Do i have any advantages/disadvantages in one over another. I have to bind these values and get/set the selected value. Which method will be best one go with?
Kindly suggest.
I tend to use a generic enumeration of SelectListItem in MVC applications. The main reason is that makes more sense when you use ViewModels with your views.
Let's say I have movies stored in a database. I represent a movie with a POCO class.
public class Movie
{
public string Genre { get; set; }
}
The page to edit the movie receive a ViewModel.
public class MovieViewModel
{
public string Genre { get; set; }
public IEnumerable<SelectListItem> GenreList
{
get
{
yield return new SelectListItem { Text = "Comedy", Value = "1" };
yield return new SelectListItem { Text = "Drama", Value = "2" };
yield return new SelectListItem { Text = "Documentary", Value = "3" };
}
}
}
The ViewModel is my model but with additional properties to personalize my view, like the list of the available genres.
Finally in my view, I populate my dropdownlist using the ASP.NET wrapper Html.DropDownListFor().
#model MvcApplication1.Models.MovieViewModel
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div>
#Html.DropDownListFor(m => m.Genre, Model.GenreList)
</div>
</body>
</html>
The selected value is then automatically chosen using the ViewModel.
#Html.DropDownListFor(m => m.branch, CommonMethod.getBranch("",Model.branch), "--Select--", new { #multiple = "multiple" })
#Html.DropDownListFor(m => m.division, CommonMethod.getDivision(Model.branch,Model.division), "--Select--", new { #multiple = "multiple" })
I have two instances of DropDownListFor. I want to set selected as true for those which have previously stored values for Model.branch and Model.division. These are string arrays of stored ids
class CommonMethod
{
public static List<SelectListItem> getDivision(string [] branchid , string [] selected)
{
DBEntities db = new DBEntities();
List<SelectListItem> division = new List<SelectListItem>();
foreach (var b in branchid)
{
var bid = Convert.ToByte(b);
var div = (from d in db.Divisions where d.BranchID == bid select d).ToList();
foreach (var d in div)
{
division.Add(new SelectListItem { Selected = selected.Contains(d.DivisionID.ToString()), Text = d.Description, Value = d.DivisionID.ToString() });
}
}
}
return division;
}
}
The returned value of division is selected as true for the selected item in the model, but on view side it is not selected.
Use a ListBoxFor instead of DropDownListFor:
#Html.ListBoxFor(m => m.branch, CommonMethod.getBranch("", Model.branch), "--Select--")
#Html.ListBoxFor(m => m.division, CommonMethod.getDivision(Model.branch, Model.division), "--Select--")
The branch and division properties must obviously be collections that will contain the selected values.
And a full example of the proper way to build a multiple select dropdown using a view model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
that would be populated in the controller:
public ActionResult Index()
{
var model = new MyViewModel();
// preselect items with values 2 and 4
model.SelectedValues = new[] { 2, 4 };
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
new SelectListItem { Value = "4", Text = "item 4" },
};
return View(model);
}
and in the view:
#model MyViewModel
...
#Html.ListBoxFor(x => x.SelectedValues, Model.Values)
It is the HTML helper that will automatically preselect the items whose values match those of the SelectedValues property.
For me it works also for #Html.DropDownListFor:
Model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new MyViewModel();
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "2", Text = "2", Selected = true },
new SelectListItem { Value = "3", Text = "3", Selected = true },
new SelectListItem { Value = "6", Text = "6", Selected = true }
};
return View(model);
}
Razor:
#Html.DropDownListFor(m => m.SelectedValues, Model.Values, new { multiple = "true" })
Submitted SelectedValues in controller looks like:
Though quite old thread but posting this answer after following other answers here, which unfortunately didn't work for me. So, for those who might have stumbled here recently or in near future, Below is what has worked for me.
This is what helped me
The catch for me was MultiSelectList class and I was using SelectList.
Don't know situation in 2012 or 2015. but, now both these helper methods #Html.DropDownListFor and #Html.ListBoxFor helper methods accept IEnumerable<SelectListItem> so you can not pass any random IEnumerable object and expect these helper methods to do the job.
These helper methods now also accept the object of SelectList and MultiSelectList classes in which you can pass the selected values directly while creating there objects.
For example see below code how i created my multi select drop down list.
#Html.DropDownListFor(model => #Model.arrSelectUsers, new MultiSelectList(Model.ListofUsersDTO, "Value", "Text", #Model.arrSelectUsers),
new
{
id = "_ddlUserList",
#class = "form-control multiselect-dropdown",
multiple = "true",
data_placeholder = "Select Users"
})
I have a class called Entity
public class Entity
{
public string Name { get; set; }
public Location Place { get; set; }
}
and one class called Location
public class Location
{
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
}
One Entity contains a Location, so I want to generate 3 dropdowns for Location.
Country
State
City
I could do it manually like
#Html.DropDownListFor(o => o.Country, new [] { new SelectListItem() { Text = "United States", Value="US" } })
<br />
#Html.DropDownListFor(o => o.State, new [] { new SelectListItem() { Text = "Some State", Value="SS" } })
<br />
#Html.DropDownListFor(o => o.City, new[] { new SelectListItem() { Text = "Some city", Value = "City" } })
But I have several places on my website that will need the exact same 3 dropdowns, like Restaurant, Hotel and other classes that also have a Location. I've tried to make a partial view that starts a new form, but I get an exception:
The model item passed into the dictionary is of type 'TestMVC3Razor.Controllers.Entity', but this dictionary requires a model item of type 'TestMVC3Razor.Controllers.Location', with this code:
#model TestMVC3Razor.Controllers.Entity
#using (Html.BeginForm())
{
#Html.Partial("LocationSelector", Model.Place)
<br />
<input type="submit" value="Submit" />
}
And the partial view is
#model TestMVC3Razor.Controllers.Location
#using (Html.BeginForm())
{
#Html.DropDownListFor(o => o.Country, new [] { new SelectListItem() { Text = "United States", Value="US" } })
<br />
#Html.DropDownListFor(o => o.State, new [] { new SelectListItem() { Text = "Some State", Value="SS" } })
<br />
#Html.DropDownListFor(o => o.City, new[] { new SelectListItem() { Text = "Some city", Value = "City" } })
}
This obviously shouldn't work, but I want to do something like it, a helper like this would be perfect
#Html.LocationSelectFor(o => o.Location)
But how do I do this? I need to generate 3 dropdowns and when I post to an action I need to get the object with bidden values.
public ActionResult(Location loc)
{
var x = String.Format("{0}, {1} - {2}", loc.City, loc.Country, loc.State);
}
How can I make this helper to create 3 dropdowns and bind values when I post?
Just create your own extension off of HtmlHelper:
public static HtmlHelperExtensions {
public static MvcString LocationSelectFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel,TProperty>> expression) {
// examine expression and build html
}
}
The trick is looking at the expression. This blog post should get you started: http://geekswithblogs.net/Madman/archive/2008/06/27/faster-reflection-using-expression-trees.aspx
Alternately, you can create an EditorTemplate for your Location class. Just google for asp.net mvc editortemplate. http://www.codecapers.com/post/Display-and-Editor-Templates-in-ASPNET-MVC-2.aspx
Personally I would stick with EditorTemplates, as you can change the view without the need to recompile typically.
You can follow this example to use expression and expression body
Get Custom Attributes from Lambda Property Expression
Or just use string expression and manipulate that as here http://www.joelscode.com/post/Use-MVC-Templates-with-Dynamic-Members-with-custom-HtmlHelper-Extensions.aspx
Following xixonia little hints I got what I needed.
#Html.EditorFor(o => o.Place, "LocationSelector",
new CreateLocation{ Country = "US", State = "A", City = "Y" })
And I have a template under
Views
|- Shared
|- EditorTemplates
LocationSelector.cshtml
#model TestMVC3Razor.Controllers.CreateLocation
#using TestMVC3Razor.Controllers
#Html.DropDownListFor(o => o.Country, Model.CountryList)
<br />
#Html.DropDownListFor(o => o.State, Model.StateList)
<br />
#Html.DropDownListFor(o => o.City, Model.CityList)
And then I made
public class CreateEntity
{
[Required]
public string Name { get; set; }
public CreateLocation Place { get; set; }
}
public class CreateLocation
{
public CreateLocation(Location location = null)
{
if (location != null)
{
Country = location.Country;
State = location.State;
City = location.City;
}
}
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
public IEnumerable<SelectListItem> CountryList
{
get
{
var list = new[]
{
new SelectListItem() { Text = "US", Value = "US" },
new SelectListItem() { Text = "BR", Value = "BR" },
new SelectListItem() { Text = "ES", Value = "ES" },
};
var selected = list.FirstOrDefault(o => o.Value == Country);
if (selected != null)
{
selected.Selected = true;
}
return list;
}
}
public IEnumerable<SelectListItem> StateList
{
get
{
var list = new[]
{
new SelectListItem() { Text = "A", Value = "A" },
new SelectListItem() { Text = "B", Value = "B" },
new SelectListItem() { Text = "C", Value = "C" },
};
var selected = list.FirstOrDefault(o => o.Value == State);
if (selected != null)
{
selected.Selected = true;
}
return list;
}
}
public IEnumerable<SelectListItem> CityList
{
get
{
var list = new[]
{
new SelectListItem() { Text = "X", Value = "X" },
new SelectListItem() { Text = "Y", Value = "Y" },
new SelectListItem() { Text = "Z", Value = "Z" },
};
var selected = list.FirstOrDefault(o => o.Value == City);
if (selected != null)
{
selected.Selected = true;
}
return list;
}
}
}
And my controller
public class HomeController : Controller
{
public ActionResult Index()
{
// can load data for edit
return View(new CreateEntity { Place = new CreateLocation(TempData["Location"] as Location) });
}
[HttpPost]
public ActionResult Index(Entity ent)
{
var loc = ent.Place;
var x = String.Format("{0} {1} {2}", loc.Country, loc.State, loc.City);
ViewBag.Result = x; // display selected values
TempData["Location"] = loc;
return Index();
}
}
I don't know if it is the best solution, but at least I can call
#Html.EditorFor(o => o.Place, "LocationSelector", obj)
from any place and have a default place selector on my website.