So I have some drop down lists in a view (apologies for the wall of code, thought it better to post to much than not enough):
//...blah...
<%=Html.DisplayFor(m=>m.PlanType.PlanTypeType) %>
<%=Html.DisplayFor(m=>m.YearLevel.YearLevelName) %>
<%=Html.DisplayFor(m=>m.Subject.Subject1) %>
//..moreblah...
rendered via an editor template (SelectList.ascx):
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SelectList>" %>
<div class="editor-label">
<%= Html.LabelFor(m => m) %>
</div>
<div class="editor-field">
<%= Html.DropDownListFor(m => m, Model,"Select an Item...") %>
<%= Html.ValidationMessageFor(m => m) %>
</div>
And a User View:
public class PlanView
{
public Plan Plan { get; private set; }
[UIHint("SelectList")]
[DisplayName("Plan Type")]
public SelectList PlanType { get; private set; }
[UIHint("SelectList")]
[DisplayName("Year Level")]
public SelectList YearLevel { get; private set; }
[UIHint("SelectList")]
[DisplayName("Subject")]
public SelectList Subject { get; private set; }
public PlanView(Plan plan)
{
Plan = plan;
PlanTypeRepository PTR = new PlanTypeRepository();
SubjectRepository SR = new SubjectRepository();
YearLevelRepository YLR = new YearLevelRepository();
PlanType = new SelectList(PTR.GetAll(), "PlanTypeID", "PlanTypeType", plan.PlanTypeID);
YearLevel = new SelectList(YLR.GetAll(), "YearLevelID", "YearLevelName", plan.PlanYearLevelID);
Subject = new SelectList(SR.GetAll(), "SubjectID", "Subject1", plan.PlanSubjectID);
}
public PlanView()
{ }
}
And the controller:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
Plan plan = PR.GetSingle(id);
PlanView pv = new PlanView(plan);
try
{
plan.PlanAuthor = collection["Plan.PlanAuthor"];
plan.PlanName = collection["Plan.PlanName"];
plan.PlanMapID = Convert.ToInt32(collection["Plan.PlanMapID"]);
plan.PlanTemplateID = Convert.ToInt32(collection["Plan.PlanTemplate"]);
plan.PlanTypeID = Convert.ToInt32(collection["PlanType"]);
plan.PlanSubjectID = Convert.ToInt32(collection["Subject"]);
plan.PlanYearLevelID = Convert.ToInt32(collection["YearLevel"]);
//UpdateModel(plan);
PR.Save();
return RedirectToAction("Details", new { id = pv.Plan.PlanID });
}
catch
{
return View(pv);
}
}
Which works. But i want to use UpdateModel() (currently commented out) in case i want to add any more fields, and also (mainly) cos i want to know how to do it. And i cant because the select lists return strings and the LINQ is expecting ints. So i have gathered that i need to write a model binder to convert the strings to ints. My attempt:
public class DropDownListBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext modelBindingContext)
{
string key = modelBindingContext.ModelName;
ValueProviderResult val = modelBindingContext.ValueProvider.GetValue(key);
try
{
if (val != null && !string.IsNullOrEmpty(val.AttemptedValue))
{
modelBindingContext.ModelState.SetModelValue(key, val);
int number;
if (int.TryParse(val.RawValue.ToString(), out number))
{
return number;
}
throw new Exception("Borked :(");
}
throw new Exception("Borked :(");
}
catch (Exception e)
{
modelBindingContext.ModelState.AddModelError(key, e.Message);
return null;
}
}
}
And in global.asax:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(SelectList), new DropDownListBinder());
}
Now if i comment out all the collection[key] manual updates in the controller and use UpdateModel() it dies in the arse saying that the data is invalid (which it is). If i place a breakpoint int the model binder it never fires so the model binder is not even excecuted.
So, am i missing something? Going about this all arse about? Thanks Internet!