Like this:
<% using (Html.BeginForm()) { %> <% for (var i = 0; i < Model.AllPages.Count; i++) { %> <fieldset> <legend> <%= Model.AllPages[i].DisplayName %> </legend> <% for (var j = 0; j < Model.AllPages[i].actions.Count; j++ ) { %> <%= Html.CheckBoxFor(x => x.AllPages[i].actions[j].IsChecked) %> <%= Html.Label(Model.AllPages[i].actions[j].DisplayName) %> } </fieldset> <% } %> <input type="submit" value="save"/> <% } %>
To understand why my solution works and yours doesn't, read about the expected wire format , which is used as the default binder for collections. Then view the generated form input field names by looking at the generated HTML source code - you will quickly see the fundamental difference in the name attribute of this check box.
Also, do not expect your entire model to be tied to a POST action. You have only one input field inside your form - a checkbox. So the only value that will be sent to the server and bound to the model. If you need other values, you can include them in hidden fields:
<% =Html.HiddenFor(x => x.AllPages[i].DisplayName) %> ... <%= Html.HiddenFor(x => x.AllPages[i].actions[j].ActionName) %> <%= Html.HiddenFor(x => x.AllPages[i].actions[j].DisplayName) %> ... and so on ...
I also highly recommend that you use editor templates instead of writing these loops in your views. They will automatically take care of creating their own names for your input fields, so you have nothing to worry about. I have gazillions of answers on this topic. Just google my name and add editor templates asp.net mvc to your search and you will get many results.
source share