I had the same issue. I fixed it with the following combination (with a little help from Darin Dimitrov--thank you):
VIEW:
<label for="optIn"><%=Html.CheckBox("optIn", ViewData["OptIn"])%>
Controller:
public ActionResult Index()
{
ViewData["Optin"] = True;
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection form, bool OptIn )
{
ViewData["Optin"] = OptIn;
}
Here's the source for the control with and without the checkbox actually checked (for reference):
Checked:
<input Length="4" checked="checked" id="optIn" name="optIn" type="checkbox" value="true" /><input name="optIn" type="hidden" value="false" />
Unchecked:
<input Length="4" id="optIn" name="optIn" type="checkbox" value="true" /><input name="optIn" type="hidden" value="false" />
So, here's how I am interpreting the behavior:
HTML will not post back the field value if the checkbox is unchecked but will post back if it is. The helper appends a hidden field after the checkbox control (value of 'False'). If the checkbox is checked, the source shows "checked = 'checked'" if it's unchecked, this does not appear. So, if checked = checked, true is passed back to the controller. If the box is unchecked, the control is not passed back so the hidden field, named the same, takes over and passes back a false. This way you have both conditions. Strange but it works. I hope this helps.