Działa to całkiem dobrze za pomocą spinacza modelu niestandardowych i regularne HTML ...
Po pierwsze, formularz HTML w składni Razor:
@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
może również być .Get
, nie ma znaczenia do tego)
Następnie, w sensie właściwym MVC posiada obiekt modelu, który reprezentuje swój złożenie formularza:
public class CheckboxListExampleModel {
public string TextboxValue { get; set; }
public List<int> CheckboxValues { get; set; }
}
I niestandardowa klasa wiążącego modelu (lubię umieszczać ją w modelu, który jest związany, więc powtórzę model utworzony powyżej, aby pokazać, gdzie powinienem go dodać.Umieszczenie go wewnątrz pozwala także spoiwo używać prywatnych ustawiające własności, co jest dobrą rzeczą):
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()
jest metoda rozszerzenie używane dla jasności, to jest tutaj:
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>()
jest także metoda rozszerzenia, ale jest to dość powszechna potrzeba i niechlujny kod, który zostawię jako ćwiczenie dla czytelnika.
I wreszcie, twoje działanie w obsłudze formularz złożyć:
[HttpPost]
public ActionResult Action([ModelBinder(typeof(CheckboxListExampleModel.Binder))] CheckboxListExampleModel model) {
// stuff
}
Pomysł nie jest zły, ale to nie działa w przypadku korzystania z formularza z innych przedmiotów niż ten. Powiedzmy na przykład, że istnieje nazwa użytkownika/hasło + zbiór pól wyboru, w ten sposób nie może on działać:/ – Erick
@Erick, oczywiście, że może działać. Twój model widoku będzie teraz zawierał proste właściwości, takie jak 'Username' i' Password' oraz właściwość kolekcji 'IEnumerable', która będzie zawierała informacje o polach wyboru. Teraz zamiast używać 'Html.EditorForModel' w twojej formie miałbyś proste' <% = Html.TextBoxFor (x => x.Username)%> 'i' <% = Html.PasswordFor (x => x.Password) %> 'i' <% = Html.EditorFor (x => x.MyCheckboxes)%> ', które będą renderować ten sam szablon edytora. –
Czytałem wiele sposobów na osiągnięcie tego, a to było zdecydowanie najbardziej eleganckie rozwiązanie. Dzięki! – JimDaniel