¿Por qué CheckBoxFor representa una etiqueta de entrada adicional y cómo puedo obtener el valor con FormCollection?

En mi aplicación ASP.NET MVC, estoy procesando una casilla usando el siguiente código:

i.ReceiveRSVPNotifications) %> 

Ahora, veo que esto representa tanto la etiqueta de entrada como una etiqueta de entrada oculta. El problema que estoy teniendo es cuando bash recuperar el valor de la casilla usando FormCollection:

 FormValues["ReceiveRSVPNotifications"] 

Obtengo el valor “verdadero, falso”. Cuando miro el HTML renderizado, puedo ver lo siguiente:

    

Entonces, la colección FormValues ​​parece unir estos dos valores ya que tienen el mismo nombre.

¿Algunas ideas?

Echa un vistazo aquí:

http://forums.asp.net/t/1314753.aspx

Esto no es un error, y de hecho es el mismo enfoque que utilizan Ruby on Rails y MonoRail.

Cuando envía un formulario con una checkbox, el valor solo se publica si la checkbox está marcada. Por lo tanto, si deja la checkbox sin marcar, no se enviará nada al servidor cuando en muchas situaciones desee que se envíe falso en su lugar. Como la entrada oculta tiene el mismo nombre que la checkbox, si la checkbox está desmarcada, recibirá un mensaje de “falso” en el servidor.

Cuando se marca la checkbox, ModelBinder se encargará automáticamente de extraer el ‘verdadero’ de ‘verdadero, falso’

Tuve el mismo problema que Shawn (arriba). Este enfoque podría ser genial para POST, pero realmente apesta para GET. Por lo tanto, implementé una extensión Html simple que simplemente saca el campo oculto.

 public static MvcHtmlString BasicCheckBoxFor(this HtmlHelper html, Expression> expression, object htmlAttributes = null) { var result = html.CheckBoxFor(expression).ToString(); const string pattern = @""; var single = Regex.Replace(result, pattern, ""); return MvcHtmlString.Create(single); } 

El problema que tengo ahora es que no quiero un cambio en el framework MVC para romper mi código. Así que tengo que asegurarme de tener cobertura de prueba que explique este nuevo contrato.

Utilizo este método alternativo para mostrar las casillas de los formularios GET:

 ///  /// Renders checkbox as one input (normal Html.CheckBoxFor renders two inputs: checkbox and hidden) ///  public static MvcHtmlString BasicCheckBoxFor(this HtmlHelper html, Expression> expression, object htmlAttributes = null) { var tag = new TagBuilder("input"); tag.Attributes["type"] = "checkbox"; tag.Attributes["id"] = html.IdFor(expression).ToString(); tag.Attributes["name"] = html.NameFor(expression).ToString(); tag.Attributes["value"] = "true"; // set the "checked" attribute if true ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData); if (metadata.Model != null) { bool modelChecked; if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked)) { if (modelChecked) { tag.Attributes["checked"] = "checked"; } } } // merge custom attributes tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); var tagString = tag.ToString(TagRenderMode.SelfClosing); return MvcHtmlString.Create(tagString); } 

Es similar al método de Chris Kemp , que está funcionando bien, excepto que este no usa el CheckBoxFor y el Regex.Replace subyacentes. Se basa en la fuente del método original Html.CheckBoxFor .

Aquí está el código fuente para la etiqueta de entrada adicional. Microsoft tuvo la amabilidad de incluir comentarios que abordan esto con precisión.

 if (inputType == InputType.CheckBox) { // Render an additional  for checkboxes. This // addresses scenarios where unchecked checkboxes are not sent in the request. // Sending a hidden input makes it possible to know that the checkbox was present // on the page when the request was submitted. StringBuilder inputItemBuilder = new StringBuilder(); inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing)); TagBuilder hiddenInput = new TagBuilder("input"); hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden)); hiddenInput.MergeAttribute("name", fullName); hiddenInput.MergeAttribute("value", "false"); inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing)); return MvcHtmlString.Create(inputItemBuilder.ToString()); } 

Creo que la solución más simple es renderizar el elemento INPUT directamente de la siguiente manera:

 " /> 

En la syntax Razor es incluso más fácil, porque el atributo ‘checked’ se representa directamente con un valor “checked” cuando se le da un valor ‘verdadero’ del lado del servidor.