CheckboxList
Das CheckboxList-EditorTemplate rendert eine Gruppe von Checkboxen für eine
Mehrfachauswahl. Der Wert ist eine IEnumerable<int> der ausgewählten Ids; die
Optionen kommen über [AdditionalMetadata("Selection", ...)]; Einbindung über
[UIHint(UiEditor.Basis.CheckboxList)]. Die Ausrichtung der Checkboxen (nebeneinander oder
nach unten) steuert [AdditionalMetadata("Direction", FlexDirection.Column)].
CheckboxList (Grundfall)
Mehrfachauswahl mit Gruppen-Beschriftung; die Einträge stehen nebeneinander, zwei davon sind vorausgewählt.
@model CheckboxListBeispielViewModel
<form class="fmh-demo-form">
@Html.EditorFor(m => m.Auswahl)
</form>
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using FMH.Komponente.Infrastruktur;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
/// <summary>
/// Der Grundfall: Mehrfachauswahl mit Gruppen-Beschriftung, zwei Einträge sind vorausgewählt.
/// </summary>
public class CheckboxListBeispielViewModel
{
[Display(Name = "Interessen")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
public IEnumerable<int> Auswahl { get; set; } = new[] { 1, 3 };
public IEnumerable<SelectListItem> Interessen { get; } = new List<SelectListItem>
{
new ("Sport", "1"),
new ("Musik", "2"),
new ("Reisen", "3"),
};
}
}
Darstellung
Das CheckboxList-EditorTemplate rendert eine Gruppe von Checkboxen für eine Mehrfachauswahl. Der Wert ist eine IEnumerable<int> mit den gewählten Ids, die Optionen stehen als SelectListItem-Liste in einer zweiten Eigenschaft des ViewModels; welche das ist, sagt UiMetadata.Basis.ListSelection.
[Display(Name = "Interessen")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
public IEnumerable<int> Auswahl { get; set; } = new[] { 1, 3 };
public IEnumerable<SelectListItem> Interessen { get; } = new List<SelectListItem>
{
new("Sport", "1"), new("Musik", "2"), new("Reisen", "3"),
};
@Html.EditorFor(m => m.Auswahl)
Der Aufruf gehört in ein Formular. Vorausgewählt ist, was in Auswahl steht: Die Werte werden mit dem Value der SelectListItem verglichen, im Beispiel also Sport und Reisen.
Die Attribute im Überblick
| Attribut | Wirkung |
|---|---|
[UIHint(UiEditor.Basis.CheckboxList)] |
Wählt die Vorlage; Standard-MVC-Mechanik, die Konstante kommt aus UiEditor.Basis (FMH.Komponente.Basis.Validierung) |
[Display(Name = "…")] |
Beschriftung über der Gruppe |
[Required] |
Pflichtangabe; die Auswahl darf dann nicht leer sein |
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(…))] |
Name der Eigenschaft mit den SelectListItem; ohne sie bleibt die Gruppe leer. Ohne View-Model kommt die Liste über EditorFor(…, additionalViewData), siehe «CheckboxList ohne View-Model» |
[AdditionalMetadata(UiMetadata.Basis.ShowGroupLabel, false)] |
Blendet die Gruppen-Beschriftung aus, siehe Beispiel «CheckboxList ohne Gruppen-Beschriftung» |
[AdditionalMetadata(UiMetadata.Basis.ElementDirection, FlexDirection.Column)] |
Anordnung der Einträge, siehe Beispiel «CheckboxList untereinander» |
[HelpText(Name = "…")] |
Ergänzender Hilfetext unter der Gruppe |
Die drei Metadaten brauchen den AdditionalMetadataProvider. Das Template liest sie aus ModelMetadata.AdditionalValues; ohne die Registrierung über AddFmhWidgetOptions() bleibt die Gruppe leer, weil schon die Auswahlliste nicht ankommt. Die Konstanten liegen in UiMetadata.Basis (Paket FMH.Komponente.Basis.Validierung), ihre Werte sind "Selection", "GroupLabel" und "Direction"; die Konstante ist der sichere Weg, die Zeichenkette der stille Fehler.
CheckboxList ohne Gruppen-Beschriftung
Mit UiMetadata.Basis.ShowGroupLabel auf false entfällt die Beschriftung über der Gruppe, die Einträge bleiben unverändert.
@model CheckboxListOhneLabelBeispielViewModel
<form class="fmh-demo-form">
@Html.EditorFor(m => m.AuswahlOhneLabel)
</form>
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using FMH.Komponente.Infrastruktur;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
/// <summary>
/// Dieselbe Auswahl ohne Gruppen-Beschriftung und ohne Vorauswahl: Der Text aus [Display]
/// bleibt am Modell, gerendert wird er nicht.
/// </summary>
public class CheckboxListOhneLabelBeispielViewModel
{
[Display(Name = "Interessen ohne Gruppen-Beschriftung")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
[AdditionalMetadata(UiMetadata.Basis.ShowGroupLabel, false)]
public IEnumerable<int> AuswahlOhneLabel { get; set; } = new List<int>();
public IEnumerable<SelectListItem> Interessen { get; } = new List<SelectListItem>
{
new ("Sport", "1"),
new ("Musik", "2"),
new ("Reisen", "3"),
};
}
}
Darstellung
Mit UiMetadata.Basis.ShowGroupLabel auf false entfällt die Beschriftung über der Gruppe. Sinnvoll, wenn der Zusammenhang schon aus der Umgebung hervorgeht, etwa in einer Tabellenzelle oder unter einer eigenen Überschrift.
[Display(Name = "Interessen ohne Gruppen-Beschriftung")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
[AdditionalMetadata(UiMetadata.Basis.ShowGroupLabel, false)]
public IEnumerable<int> AuswahlOhneLabel { get; set; } = new List<int>();
Zwei Dinge dazu:
[Display]bleibt trotzdem sinnvoll. Der Text verschwindet nur aus der Anzeige; Validierungsmeldungen sprechen die Eigenschaft weiterhin mit diesem Namen an.- Ohne Vorauswahl startet die Gruppe leer, hier absichtlich:
Auswahlist eine leere Liste.
Die Konstante heisst ShowGroupLabel, ihr Wert ist "GroupLabel". UiMetadata.Basis.ShowLabel ist derselbe Schlüssel unter anderem Namen.
CheckboxList ohne View-Model
Das ViewModel ist nur eine lokale Variable, etwa in einer Sidebar. Die Liste kommt dann über den zweiten Parameter von EditorFor ins Template.
@* Bewusst ohne @model: Das ViewModel ist eine lokale Variable, wie in einer Sidebar oder einem
Layout-Partial. Der Behälter im Template ist damit nicht dieses Objekt, darum reicht der zweite
Parameter von EditorFor das Objekt mit; seine Eigenschaften landen in der ViewData des Templates. *@
@{
var auswahl = new CheckboxListBeispielViewModel();
}
<form class="fmh-demo-form">
@Html.EditorFor(m => auswahl.Auswahl, auswahl)
</form>
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using FMH.Komponente.Infrastruktur;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
/// <summary>
/// Der Grundfall: Mehrfachauswahl mit Gruppen-Beschriftung, zwei Einträge sind vorausgewählt.
/// </summary>
public class CheckboxListBeispielViewModel
{
[Display(Name = "Interessen")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
public IEnumerable<int> Auswahl { get; set; } = new[] { 1, 3 };
public IEnumerable<SelectListItem> Interessen { get; } = new List<SelectListItem>
{
new ("Sport", "1"),
new ("Musik", "2"),
new ("Reisen", "3"),
};
}
}
Darstellung
Ist das ViewModel nur eine lokale Variable, etwa in einer Sidebar oder einem Layout-Partial, gibt der zweite Parameter von EditorFor das Objekt mit. Das Template findet die Liste dann in der ViewData statt am Behälter:
@{
var auswahl = new CheckboxListBeispielViewModel();
}
@Html.EditorFor(m => auswahl.Auswahl, auswahl)
Die Liste nennt hier UiMetadata.Basis.ListSelection, gesucht wird aber gleich. Die Vorauswahl kommt aus dem Wert der Eigenschaft, hier die Ids 1 und 3.
Warum das nötig ist, in welcher Reihenfolge das Template sucht, die Variante mit anonymem Objekt und wie das Feld beim Absenden heisst (auswahl.Auswahl), steht ausführlich im Beispiel «DropdownList ohne View-Model» auf der Seite DropdownList.
CheckboxList untereinander
Mit UiMetadata.Basis.ElementDirection auf FlexDirection.Column stehen die Einträge untereinander statt nebeneinander.
@model CheckboxListSpalteBeispielViewModel
<form class="fmh-demo-form">
@Html.EditorFor(m => m.AuswahlSpalte)
</form>
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Controls;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using FMH.Komponente.Infrastruktur;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
/// <summary>
/// Dieselbe Auswahl, Einträge untereinander statt nebeneinander.
/// </summary>
public class CheckboxListSpalteBeispielViewModel
{
[Display(Name = "Interessen")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
[AdditionalMetadata(UiMetadata.Basis.ElementDirection, FlexDirection.Column)]
public IEnumerable<int> AuswahlSpalte { get; set; } = new[] { 1, 3 };
public IEnumerable<SelectListItem> Interessen { get; } = new List<SelectListItem>
{
new ("Sport", "1"),
new ("Musik", "2"),
new ("Reisen", "3"),
};
}
}
Darstellung
Standardmässig stehen die Einträge nebeneinander (FlexDirection.Row). Mit UiMetadata.Basis.ElementDirection auf FlexDirection.Column stehen sie untereinander, jeder auf einer eigenen Zeile.
[Display(Name = "Interessen")]
[UIHint(UiEditor.Basis.CheckboxList)]
[AdditionalMetadata(UiMetadata.Basis.ListSelection, nameof(Interessen))]
[AdditionalMetadata(UiMetadata.Basis.ElementDirection, FlexDirection.Column)]
public IEnumerable<int> AuswahlSpalte { get; set; }
FlexDirection liegt in FMH.Komponente.Basis.Ui.Controls.
| Wert | Wirkung |
|---|---|
FlexDirection.None |
wie Row, also der Standard ohne Angabe |
FlexDirection.Row |
Einträge nebeneinander, CSS-Klasse fmh-flex-direction-row |
FlexDirection.Column |
Einträge untereinander, CSS-Klasse fmh-flex-direction-column |
Die Gruppen-Beschriftung ist Teil desselben Flex-Containers: bei Column steht sie über den Einträgen, bei Row in derselben Zeile. Beide Angaben lassen sich frei kombinieren, also auch Spaltenanordnung ohne Beschriftung.
Dieselbe Anordnung kennt RadioList mit derselben Konstante, dort für die Einfachauswahl.