Saturday, December 27, 2014

Working with List Controls in ASP.NET MVC

Unfortunately, Microsoft does not provide default Scaffolding for any List controls in ASP.NET MVC such as the DropDownList, RadioButtonList or CheckBoxList controls as was provided earlier in ASP.NET Web Forms.

Therefore, for the time being, developers are required to come up with their own solutions for implementing Scaffolding or Model-binding support for these controls.

Of the 3 types of controls, the DropDownList control is by far the easiest to manage:

In your C# code, you need to create the following Model properties:
public IList<SelectListItem> Countries { get; set; }

 

[Required]

public string SelectedCountry { get; set; }



Then in your Controller class, you need to add the appropriate model binding code:



SampleViewModel model = new SampleViewModel();

model.Countries = new List<SelectListItem>();

model.Countries.Add(new SelectListItem{Text = "USA", Value = "USA"});

model.Countries.Add(new SelectListItem { Text = "India", Value = "India", Selected = true});

model.Countries.Add(new SelectListItem { Text = "Canada", Value = "Canada" });



In your Razor View, you simply use the following Html Helper:



<div class="form-group">

    @Html.LabelFor(model => model.SelectedCountry, htmlAttributes: new { @class = "control-label col-md-2" })

    <div class="col-md-10">

        @Html.DropDownListFor(model => model.SelectedCountry, Model.Countries, new { htmlAttributes = new { @class = "form-control" } })

        @Html.ValidationMessageFor(model => model.SelectedCountry, "", new { @class = "text-danger" })

    </div>

</div>

This is an article which describes how to do this in a bit more detail: http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx

With the RadioButtonList and CheckboxList controls, the situation becomes a bit more complex, particularly with the Checkbox control which provides significantly different handling than what was provided with ASP.NET Web Forms.

You have to start out by creating your own custom Class to handle support for your RadioButtonList and CheckboxList controls such as the following:



public class GenericListItem

    {

        public int Value { get; set; }

        public string Text { get; set; }

 

        public string Checked {

            get { return "checked"; }

        }

 

 

        public bool Selected { get; set; }

 

        /// <summary>

        /// Default constructor

        /// </summary>

        public GenericListItem()

        {

            //Default all ListItems to an initial value of unchecked/false

            this.Selected = false;

        }

 

        /// <summary>

        /// Overloaded constructor

        /// </summary>

        /// <param name="Value"></param>

        /// <param name="Text"></param>

        /// <param name="Selected"></param>

        public GenericListItem(int Value, string Text, bool Selected = false)

        {

            this.Value = Value;

            this.Text = Text;

            this.Selected = Selected;

        }

 

    }



In your Controller class, you can add similar model binding code as what was done for the DropDownList control:




model.RadioButtonList = new List<GenericListItem>();

model.RadioButtonList.Add(new GenericListItem { Text = "RadioListItem1", Value = 1 });

model.RadioButtonList.Add(new GenericListItem { Text = "RadioListItem2", Value = 2, Selected = true });

model.RadioButtonList.Add(new GenericListItem { Text = "RadioListItem3", Value = 3 });

 

model.CheckBoxList = new List<GenericListItem>();

model.SelectedCheckbox = "CheckboxListName";

model.CheckBoxList.Add(new GenericListItem { Text = "CheckBoxListItem1", Value = 1, Selected = true});

model.CheckBoxList.Add(new GenericListItem { Text = "CheckBoxListItem2", Value = 2, Selected = true });

model.CheckBoxList.Add(new GenericListItem { Text = "CheckBoxListItem3", Value = 3 });



In your Razor View, you have to write some custom Razor code in order to achieve the desired rendering:



<div class="form-group">

   @Html.LabelFor(model => model.SelectedRadioButton, htmlAttributes: new { @class = "control-label col-md-2" })

   <div class="col-md-10">

       @foreach (GenericListItem radioitem in Model.RadioButtonList)

       {

           if (radioitem.Selected)

           {

               @Html.RadioButtonFor(model => model.RadioButtonList, radioitem.Value, htmlAttributes: new { @checked = radioitem.Checked }) @Html.Label(radioitem.Text)

           }

           else

           {

               @Html.RadioButtonFor(model => model.RadioButtonList, @radioitem.Value) @Html.Label(@radioitem.Text)

           }

 

       }

       @Html.ValidationMessageFor(model => model.SelectedRadioButton, "", new { @class = "text-danger" })

   </div>

</div>

<div class="form-group">

   @Html.LabelFor(model => model.SelectedCheckbox, htmlAttributes: new { @class = "control-label col-md-2" })

   <div class="col-md-10">

       @foreach (GenericListItem checkboxItem in Model.CheckBoxList)

       {

           

           @Html.CheckBox(Model.SelectedCheckbox, checkboxItem.Selected, new { value = @checkboxItem.Value }) @Html.Label(checkboxItem.Text)

       }

   </div>

</div>


You will notice that even though there is a CheckBoxFor Html Helper, I avoided using it due to the lack of support for the value attribute.  

If you are like me and would like to see Microsoft add support for Scaffolding/Model-binding support for List Controls especially for the CheckBoxList and RadioButtonList controls, vote for these User Voice items:

https://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/5849005-provide-html-checkboxlist-and-html-radiobuttonlist

https://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/488893-better-binding-support-for-checkbox-lists

No comments:

Post a Comment