2011-02-03 18 views
12

Estoy buscando aquí para encontrar una manera rápida y fácil de vincular una lista de elementos de lista de casilla de verificación cuando se produce la devolución de datos en el modelo.¿Hay alguna forma de vincular una lista de casilla de verificación a un modelo en asp.net mvc

Aparentemente la forma común de hacerlo ahora parece hacerlo así form.GetValues("checkboxList")[0].Contains("true"); Parece doloroso y no exactamente seguro.

¿Hay una manera de enlazar una lista de casilla de verificación (que se crean con o sin un ayudante en la vista) o incluso un conjunto de datos para que importa durante la fase de UpdateModel(myViewModel, form.ToValueProvider()); que rellenar una IList<string> o string[] interior de la modelo?

Respuesta

9

Se podría empezar con un modelo:

public class MyViewModel 
{ 
    public int Id { get; set; } 
    public bool IsChecked { get; set; } 
} 

luego de un controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new[] 
     { 
      new MyViewModel { Id = 1, IsChecked = false }, 
      new MyViewModel { Id = 2, IsChecked = true }, 
      new MyViewModel { Id = 3, IsChecked = false }, 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(IEnumerable<MyViewModel> model) 
    { 
     // TODO: Handle the user selection here 
     ... 
    } 
} 

vistas (~/Views/Home/Index.aspx):

<% using (Html.BeginForm()) { %> 
    <%=Html.EditorForModel() %> 
    <input type="submit" value="OK" /> 
<% } %> 

Y, finalmente, un editor de plantillas correspondiente:

<%@ Control 
    Language="C#" 
    Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.MyViewModel>" %> 
<%= Html.HiddenFor(x => x.Id) %> 
<%= Html.CheckBoxFor(x => x.IsChecked) %> 

Ahora cuando envíe el formulario en la acción POST, obtendrá la lista de valores seleccionados junto con su identificación.

+0

idea no es mala, pero no funciona cuando se utiliza un formulario con otros artículos que esto. Digamos, por ejemplo, que hay un nombre de usuario/contraseña + una colección de casillas, de esta manera no puede funcionar:/ – Erick

+2

@Erick, por supuesto que puede funcionar. Su modelo de vista ahora contendrá propiedades simples como 'Nombre de usuario' y' Contraseña' y una propiedad de colección 'IEnumerable ' que contendrá la información de las casillas de verificación. Ahora, en lugar de usar 'Html.EditorForModel' en tu formulario, tendrías' '% simple = Html.TextBoxFor (x => x.Username)%>' y '<% = Html.PasswordFor (x => x.Password) %> 'y a' <% = Html.EditorFor (x => x.MyCheckboxes)%> 'que mostrarán la misma plantilla de editor. –

+0

He leído muchas formas de lograr esto, y esta fue de lejos la solución más elegante. ¡Gracias! – JimDaniel

9

Aquí está la manera rápida y fácil. Simplemente configure el atributo value dentro de sus elementos de entrada checkbox y asígneles el mismo name. Si yo estaba llevando a cabo esto en un sitio, me gustaría crear un método CheckBox auxiliar que lleva name, value y isChecked parámetros, pero aquí es la vista con sólo el código HTML necesario:

<% using (Html.BeginForm()) { %> 
    <p><input type="checkbox" name="checkboxList" value="Value A" /> Value A</p> 
    <p><input type="checkbox" name="checkboxList" value="Value B" /> Value B</p> 
    <p><input type="checkbox" name="checkboxList" value="Value C" /> Value C</p> 
    <p><input type="checkbox" name="checkboxList" value="Value D" /> Value D</p> 
    <p><input type="checkbox" name="checkboxList" value="Value E" /> Value E</p> 
    <p><input type="checkbox" name="checkboxList" value="Value F" /> Value F</p> 
    <input type="submit" value="OK" /> 
<% } %> 

en su controlador:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Index(IEnumerable<string> checkboxList) 
{ 
    if (checkboxList != null) 
    { 
     ViewData["Message"] = "You selected " + checkboxList.Aggregate("", (a, b) => a + " " + b); 
    } 
    else 
    { 
     ViewData["Message"] = "You didn't select anything."; 
    } 

    return View(); 
} 

El parámetro IEnumerable<string> (puede hacerlo IList<string> si lo desea) contendrá solo los valores de los elementos marcados. Será null si no se marca ninguno de los cuadros.

+0

Creo que no es una buena idea poner código html nativo allí porque será un dolor si el usuario quiere vincular el modelo a las casillas de verificación – tugberk

+0

@tugberk, dije que usaría un método auxiliar en el código de producción. Solo estaba tratando de mostrar la respuesta a la pregunta original. Añadiré el código del método de ayuda. – CoderDennis

+2

Esta es la respuesta correcta. Si intenta utilizar los helles 'Html.CheckBox()' incorporados, ** insisten ** en insertar campos ocultos con 'value =" false "', y eso interfiere con el enlace del modelo. – Yuck

0

Esto funciona bastante bien utilizando un aglutinante de modelos personalizados y HTML normal ...

En primer lugar, su formulario HTML en Razor sintaxis:

@using (Html.BeginForm("Action", "Controller", FormMethod.Post)) { 
    <ol> 
     <li><input type="textbox" name="tBox" value="example of another form element" /></li> 

     <li><input type="checkbox" name="cBox" value="1" /> One</li> 
     <li><input type="checkbox" name="cBox" value="2" /> Two</li> 
     <li><input type="checkbox" name="cBox" value="3" /> Three</li> 
     <li><input type="checkbox" name="cBox" value="4" /> Four</li> 
     <li><input type="checkbox" name="cBox" value="5" /> Five</li> 

     <li><input type="submit" /></li> 
    </ol> 
} 

(FormMethod.Post también podría ser .Get, no importa para esto)

Luego, en el buen sentido MVC tener un objeto de modelo que representa el envío de formularios:

public class CheckboxListExampleModel { 
    public string TextboxValue { get; set; } 
    public List<int> CheckboxValues { get; set; } 
} 

Y una clase de encuadernador de modelo personalizado (me gusta poner esto dentro del modelo encuadernado, así que repetiré el modelo creado arriba para mostrar dónde lo agregaría.Si lo coloca en el interior también permite que el ligante a utilizar emisores de propiedad privada, que es una buena cosa):

public class CheckboxListExampleModel { 
    public string TextboxValue { get; private set; } 
    public List<int> CheckboxValues { get; private set; } 

    public class Binder : DefaultModelBinder { 
     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
      var model = new CheckboxListExampleModel(); 

      model.TextboxValue = bindingContext.GetValueAsString("tBox"); 

      string checkboxCsv = bindingContext.GetValueAsString("cBox"); 
      // checkboxCsv will be a comma-separated list of the 'value' attributes 
      // of all the checkboxes with name "cBox" which were checked 
      model.CheckboxValues = checkboxCsv.SplitCsv<int>(); 

      return model; 
     } 
    } 
} 

.GetValueAsString() es un método de extensión utilizada para mayor claridad, aquí está:

public static string GetValueAsString(this ModelBindingContext context, string formValueName, bool treatWhitespaceAsNull = true) { 
     var providerResult = context.ValueProvider.GetValue(formValueName); 
     if (providerResult.IsNotNull() && !providerResult.AttemptedValue.IsNull()) { 
      if (treatWhitespaceAsNull && providerResult.AttemptedValue.IsNullOrWhiteSpace()) { 
       return null; 
      } else { 
       return providerResult.AttemptedValue.Trim(); 
      } 
     } 
     return null; 
    } 

.SplitCsv<T>() es también un método de extensión, pero es una necesidad bastante común y un código lo suficientemente complicado como para dejarlo como un ejercicio para el lector.

Y, por último, su acción para manejar el envío de formulario:

[HttpPost] 
public ActionResult Action([ModelBinder(typeof(CheckboxListExampleModel.Binder))] CheckboxListExampleModel model) { 
    // stuff 
} 
Cuestiones relacionadas