2011-02-03 9 views
12

sto cercando qui di trovare un modo rapido e semplice per associare un elenco di voci di elenco casella di controllo quando si verifica il postback nel modello.C'è un modo per legare un elenco casella di controllo per un modello in asp.net mvc

Apparentemente il modo comune per farlo ora sembra farlo così form.GetValues("checkboxList")[0].Contains("true"); Sembra doloroso e non esattamente sicuro.

C'è un modo per associare un elenco di casella di controllo (che vengono creati con o senza un aiuto nella vista) o addirittura una matrice di dati per quel che conta durante la fase UpdateModel(myViewModel, form.ToValueProvider()); che popolare un IList<string> o string[] all'interno della modello ?

risposta

9

Si potrebbe iniziare con un modello:

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

poi un controller:

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 
     ... 
    } 
} 

a View (~/Views/Home/Index.aspx):

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

E infine un corrispondente editor di modelli:

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

Ora quando si invia il modulo nell'azione POST si otterrà l'elenco dei valori selezionati insieme al loro id.

+0

idea non è male, ma non funziona quando si utilizza un modulo con altri elementi di questo. Per esempio, c'è un nome utente/password + una raccolta di checkbox, in questo modo non può funzionare:/ – Erick

+2

@Erick, naturalmente che può funzionare. Il tuo modello di vista ora conterrà proprietà semplici come 'Username' e' Password' e una collezione 'IEnumerable ' che conterrà le informazioni sulle caselle di controllo. Ora invece di usare 'Html.EditorForModel' nel tuo form avresti semplice' <% = Html.TextBoxFor (x => x.Username)%> 'e' <% = Html.PasswordFor (x => x.Password) %> 'e a' <% = Html.EditorFor (x => x.MyCheckboxes)%> 'che renderizza lo stesso modello di editor. –

+0

Ho letto molti modi per realizzare questo, e questa era di gran lunga la soluzione più elegante. Grazie! – JimDaniel

9

Ecco il modo semplice e veloce. Basta impostare l'attributo value all'interno degli elementi di input checkbox e assegnare loro lo stesso name. Se mi è stato l'attuazione del presente in un sito, vorrei creare un metodo CheckBox supporto che prende name, value e isChecked parametri, ma qui è la vista con solo il codice HTML necessario:

<% 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" /> 
<% } %> 

nel controller:

[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(); 
} 

Il parametro IEnumerable<string> (è possibile farlo IList<string> se si desidera) conterrà solo i valori degli elementi selezionati. Sarà null se nessuna delle caselle è selezionata.

+0

Penso che non sia una buona idea inserire il codice html nativo perché sarebbe un problema se l'utente desidera associare il modello alle caselle di controllo – tugberk

+0

@tugberk, ho detto che avrei usato un metodo di supporto nel codice di produzione. Stavo solo cercando di mostrare la risposta alla domanda originale. Aggiungerò il codice del metodo di supporto. – CoderDennis

+2

Questa è la risposta corretta. Se si tenta di utilizzare gli helper 'Html.CheckBox()' incorporati essi ** insistono ** sull'inserimento di campi nascosti con 'value =" false "', e questo interferisce con il binding del modello. – Yuck

0

Questo funziona abbastanza bene con un modello personalizzato legante e regolare HTML ...

In primo luogo, il modulo HTML in Razor sintassi:

@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 potrebbe anche essere .Get, non importa per questo)

Poi, nel senso proprio MVC avere un oggetto del modello che rappresenta il modulo di invio:

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

E una classe di raccoglitore modello personalizzata (mi piace inserire questo modello all'interno del modello, quindi ripeterò il modello creato sopra per mostrare dove lo aggiungerei.Riposte in inoltre permette il legante da usare setter di proprietà privata, che è una buona 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() è un metodo di estensione utilizzato per chiarezza, qui è:

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>() è anche un metodo di estensione, ma è un codice abbastanza comune e abbastanza confidenziale da lasciarlo come esercizio per il lettore.

E, infine, la vostra azione per gestire il modulo di conferma:

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