views:

53

answers:

3

Hi,

I know there is a ListBoxFor extension method among the ASP.NET MVC Html helper extension methods, but I always thought that a checkbox list is more user-friendly than a list box.

There was a very convenient CheckBoxList control in good old WebForms, but obviously that is out of the picture now.

The question is, why is there no way in ASP.NET MVC to create a check box list? How can I write my own extension method that creates a check box list and behaves in a similar way ListBoxFor behaves?

A: 

You might be interested in CheckBoxList Helper for MVC article by Jeremiah Clark (unfortunately it's dated Nov 2008 and concerns MVC 1).

Alexander Prokofyev
@Alexander - The article is good, but it is not written with strongly typed HTML helpers in mind.
Venemo
A: 

While Microsoft employees are probably the only ones that can answer why such helper method doesn't exist you could try:

Model:

public class MyViewModel
{
    public bool[] Values { get; set; }
}

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel 
        { 
            Values = new[] { true, false, true, false }
        });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

View:

<% using (Html.BeginForm()) { %>
    <%: Html.EditorFor(x => x.Values) %>
    <input type="submit" value="OK" />
<% } %>

As you can see EditorFor will handle everything that's needed.

Darin Dimitrov
@Darin - This is a nice idea, but as I said, I'd like to have something similar to the behaviour of `ListBoxFor`.
Venemo
Can you be a little more specific? `ListBoxFor` generates `<select>` and accepts different types. What exactly do you need?
Darin Dimitrov
+1  A: 

Here is a strongly typed HtmlHelper for CheckBoxListFor that handles selected items as an array in your viewdata model. I chose not to wrapper the Html.CheckBox or Html.CheckBoxFor methods as I don't want the hidden "false" fields in my checkbox lists.

Please feel free to improve on this and repost :-)

//View

<%: Html.CheckBoxListFor(model => model.FreightTypeIds, FreightTypeMultiSelectList)  %>

//Controller

    public ActionResult SomeAction(int[] FreightTypeIds)
    {
       //...

       return View();
    }


//Extension
        public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty[]>> expression, MultiSelectList multiSelectList, object htmlAttributes = null)
        {
            //Derive property name for checkbox name
            MemberExpression body = expression.Body as MemberExpression;
            string propertyName = body.Member.Name;

            //Get currently select values from the ViewData model
            TProperty[] list = expression.Compile().Invoke(htmlHelper.ViewData.Model);

            //Convert selected value list to a List<string> for easy manipulation
            List<string> selectedValues = new List<string>();

            if (list != null)
            {
                selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); });
            }

            //Create div
            TagBuilder divTag = new TagBuilder("div");
            divTag.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);

            //Add checkboxes
            foreach (SelectListItem item in multiSelectList)
            {
                divTag.InnerHtml += String.Format("<div><input type=\"checkbox\" name=\"{0}\" id=\"{0}_{1}\" " +
                                                    "value=\"{1}\" {2} /><label for=\"{0}_{1}\">{3}</label></div>",
                                                    propertyName,
                                                    item.Value,
                                                    selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "",
                                                    item.Text);
            }

            return MvcHtmlString.Create(divTag.ToString());
        }
Rob