Wednesday, May 23, 2012

Foray into custom model binders

I have a complex viewmodel
public class ScenarioCreationDTO
  {
    [Required]
    [StringLength(500)]
    public string Comments { get; set; }
    [Required]
    public IEnumerable<int> PriceLists { get; set; }
    public IEnumerable<PriceListCurrencyDTO> Currencies { get; set; }
    public IEnumerable<PriceListCountryDTO> Countries { get; set; }
  }
Currencies has a compound key. How do I get binding to work for either checkBoxList or RadioButtons? Sometimes the user is allowed to select multiple, other times not. Perhaps the problem was in the view?
<tbody>
                                    @foreach (SelectListItem item in ViewBag.CurrencySelect)
                                    { 
                                        <tr>
                                            <td>
                                                @if (ViewBag.MultipleCurrencies)
                                                {
                                                    @Html.RadioButton("currencies", item.Value, item.Selected)
                                                }
                                                @Html.Label(item.Text)
                                            </td>
                                        </tr>
                                    }
                                </tbody>
I did not find a RadioButtonList helper, nor a RadioButtonFor<T> that took multiple values. Thanks to Msdn magazine and Buildstarted.com I now have a custom model binder.
protected override void OnApplicationStarted()
    {
      base.OnApplicationStarted();
      ModelBinders.Binders.Add(typeof(PriceListCurrencyDTO),new PriceListCurrencyBinder());

- global.asax.cs
public class PriceListCurrencyBinder:IModelBinder
  {
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
      var selected = value.AttemptedValue;
      var result = Shared.SyntaxSugar.Helpers.Deserialize<PriceListCurrencyDTO>(selected);
      return result;
    }
  }

var currencySelect=currencies.Select(c => new SelectListItem()
      {
        Text = c.CurrencyCode,
        Value = Shared.SyntaxSugar.Helpers.Serialize(c),
        Selected = priceListCurrenciesSelected != null && priceListCurrenciesSelected.Any(plc=>c.PriceListID==plc.PriceListID && c.CurrencyCode==plc.CurrencyCode)
      }).ToArray();
      ViewBag.CurrencySelect = currencySelect;
[HttpPost]
    public virtual ActionResult Create(byte regionID, Int64 dealID, Model.ViewModel.Scenarios.ScenarioCreationDTO data){
//...
}
and finally the view
<tbody>
                                    @foreach (SelectListItem item in ViewBag.CurrencySelect)
                                    { var i=-1; i++;
                                        <tr>
                                            <td>
                                                @if (ViewBag.MultipleCurrencies)
                                                {
                                                    @Html.RadioButton("currencies["+i+"]", item.Value, item.Selected)
                                                }
                                                @Html.Label(item.Text)
                                            </td>
                                        </tr>
                                    }
                                </tbody>

No comments:

Post a Comment