DropDownList not working 100% in ASP.Net MVC
I am quite confused with how to effectively use the Html.DropDownList helper for ASP.NET MVC.
Background: I have a 5-page form, which saves data to the form each time "Next" is clicked. Users may navigate back and forth between sections, so previous sections will already be pre-populated with previously-entered data.
This works for TextBoxes. But not DropDownLists. I have tried a load of different methods, including:
- How to add static list of items in MVC Html.DropDownList()
- Setting selected item to DropdownList in MVC Application?
I have a ViewModel such taht I have got my lists and my Model (a LINQ-to-SQL generated class) as properties. eg:
public class ConsultantRegistrationFormViewModel
{
public IConsultantRegistration ConsultantRegistration { get; private set; }
public SelectList Titles { get; private set; }
public SelectList Countries { get; private set; }
public SelectList Currencies { get; private set; }
public int CurrentSection { get; private set; }
private ConsultantRegistrationFormViewModel(IConsultantRegistration consultantRegistration)
{
ConsultantRegistration = consultantRegistration;
CurrentSection = 1;
Titles = new SelectList(new string[] { "Mr", "Mrs", "Miss", "Ms", "Dr", "Sir" });
Countries = new SelectList(countries.Select(q => q.Name));
Currencies = new SelectList(currencies,"CurrencyCode","FriendlyForm");
}
}
My Controller's Edit Action on GET looks like:
public class ConsultantRegistrationController : Controller
{
public IConsultantRegistrationRepository ConsultantRegistrationRepository { get; private set; }
public ICountryRepository CountryRepository { get; private set; }
public IEnumerable<ICountry> Countries { get; private set; }
public ConsultantRegistrationController()
{
ConsultantRegistrationRepository = RepositoryFactory.CreateConsultantRegistrationRepository();
CountryRepository = RepositoryFactory.CreateCountryRepository();
Countries = CountryRepository.GetCountries().ToArray();
}
public ActionResult Edit(Guid id, int sectionIndex)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
SelectList bankBranchCountriesSelectList = new SelectList(Countries, "BankBranchCountry", "CountryName", consultantRegistration.BankBranchCountry);
ViewData["bankBranchCountrySelectList"] = bankBranchCountriesSelectList;
return View(new ConsultantRegistrationFormViewModel(consultantRegistration,sectionIndex, Countries,Currencies));
}
}
With my View doing:
<%: Html.DropDownList("ConsultantRegistration.BankBranchCountry",ViewData["bankBranchCountrySelectList"] as SelectList) %>
This gives me the error:
DataBinding: 'IWW.ArrowPay.ConsultantRegistration.Data.Country' does not contain a property with the name 'BankBranchCountry'.
Which it does, have a look at the schema of this property:
public interface IConsultantRegistration
{
Guid ID { get; set; }
[DisplayName("Branch Countr开发者_如何学编程y")]
string BankBranchCountry { get; set; }
}
(My LINQ-to-SQL type ConsultantRegistration implemented IConsultantRegistration)
It seems that it is trying to bind to the wrong type, though?
If I use this in my view (and use my Controller's Countries property):
<%: Html.DropDownList("ConsultantRegistration.BankBranchCountry ",Model.Countries,"(select a Country)") %>
I get the saved value fine, but my model doesn't update on POST.
And if I use this in my view:
<%: Html.DropDownListFor(model=>model.ConsultantRegistration.BankBranchCountry ",Model.Countries,"(select a Country)") %>
I get the list, and it POSTs the selected value back, but does not pre-select the currently selected item in my model on the view.
So I have a bit of the solution all over the place, but not all in one place.
Hope you can help fill in my ignorance.
Ok, I solved it. Proper hacky, but it gets the job done.
I'm using the ViewData in my view:
<%: Html.DropDownList("bankBranchCountrySelectList", ViewData["bankBranchCountrySelectList"] as SelectList)%>
With the following in my controller:
public ActionResult Edit(Guid id, int sectionIndex)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
ViewData["bankBranchCountrySelectList"] = Countries.Select(q => new SelectListItem() { Text = q.Name, Value = q.Name, Selected = (q.Name.Trim().Equals(consultantRegistration.BankBranchCountry, StringComparison.InvariantCultureIgnoreCase)) }); // bankBranchCountriesSelectList;
return View(new ConsultantRegistrationFormViewModel(consultantRegistration,sectionIndex, Countries,Currencies));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, int sectionIndex, FormCollection formValues)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
UpdateModel(consultantRegistration);
ViewData["bankBranchCountrySelectList"] = Countries.Select(q => new SelectListItem() { Text = q.Name, Value = q.Name, Selected = (q.Name.Trim().Equals(consultantRegistration.BankBranchCountry, StringComparison.InvariantCultureIgnoreCase)) });
IEnumerable<RuleViolation> ruleViolations = consultantRegistration.GetRuleViolations(sectionIndex);
if (ruleViolations.Count() == 0)
{
// ...
}
else
{
ModelState.AddRuleViolations(ruleViolations);
return View(new ConsultantRegistrationFormViewModel(consultantRegistration, sectionIndex, Countries, Currencies));
}
}
Not ideal and breaks clean coding. No idea why it works, but that seems to be what MVC is all about with "convention over configuration".
This article was written with Multi-Select Lists in mind, but the principle applies equally to a single-selection drop down list:
http://www.stevefenton.co.uk/Content/Blog/Date/201002/Blog/How-To-Handle-Multiple-Select-Lists-In-ASP-NET-MVC/
精彩评论