Template-Namen und Metadaten-Schlüssel
Ein ViewModel-Feld mit FMH-Template braucht oft zwei Angaben: welches Template es rendert und wie dieses Template konfiguriert ist. Dafür gibt es zwei Einstiege. UiEditor und UiDisplay gehören zu [UIHint], UiMetadata gehört zu [AdditionalMetadata]. Diese Seite erklärt, warum das so getrennt ist.
Welcher Einstieg wohin gehört
| Attribut | Einstieg | Inhalt der Konstanten |
|---|---|---|
[AdditionalMetadata] |
UiMetadata.<Komponente> |
Schlüssel, die ein Template neben dem Wert ausliest, etwa die Eigenschaft mit der Auswahlliste |
[UIHint] |
UiDisplay.<Komponente> |
Name eines DisplayTemplates, also der Dateiname unter Views/Shared/DisplayTemplates |
[UIHint] |
UiEditor.<Komponente> |
Name eines EditorTemplates, also der Dateiname unter Views/Shared/EditorTemplates |
[Display(Name = "Land")]
[UIHint(UiEditor.Basis.DropdownList)]
[AdditionalMetadata(UiMetadata.Basis.DropdownListSelection, nameof(Laender))]
public string Land { get; set; }
Die Regel ist damit einfach: In [UIHint] steht nur UiEditor oder UiDisplay, in [AdditionalMetadata] nur UiMetadata. Weder String-Literale wie "Selection" noch die alten Konstanten aus MvcConst und DisplayConst gehören mehr in ein ViewModel. Das Literal funktioniert zwar, weil der Wert derselbe ist, ein Tippfehler fällt aber erst zur Laufzeit auf. MvcConst und DisplayConst sind als [Obsolete] markiert und nennen ihren neuen Ort.
Warum Template-Namen und Schlüssel getrennt sind
Ein falscher Wert in [UIHint] meldet keinen Fehler. Findet ASP.NET kein Template mit dem angegebenen Namen, rendert es still das Standardfeld für den Datentyp. Lägen Schlüssel und Template-Namen in derselben Klasse, böte IntelliSense nach UiEditor.Basis. auch DropdownListSelection an, und [UIHint(UiEditor.Basis.DropdownListSelection)] würde kompilieren. Das Feld sähe danach einfach falsch aus. Getrennt bietet jeder Einstieg nur Werte an, die in sein Attribut passen.
Ein Schlüssel gehört nicht zu genau einem Template. UiMetadata.Basis.DropdownListSelection lesen ComboboxList, DropdownList, MultiselectList und RadioList, UiMetadata.Basis.ShowLabel liest der Richtext-Editor der Komponente RichText. Unter einem einzelnen Template-Namen hätten solche Schlüssel keinen eindeutigen Platz.
Warum Basis mehrfach vorkommt
UiEditor, UiDisplay und UiMetadata sind Namespaces, und jede Komponente steuert darin eine eigene Klasse bei, benannt nach der Komponente: UiEditor.Basis, UiEditor.FileUpload, UiMetadata.Basis usw. Namespaces verschmelzen über Assemblygrenzen, Klassen nicht. Nur so zeigt IntelliSense nach UiEditor. genau die Komponenten, die das Projekt referenziert, und jedes Paket kann seine Namen beisteuern, ohne die anderen zu kennen.
Die Kehrseite: Die Klasse Basis gibt es in allen drei Namespaces. Deshalb die Einstiege immer voll ausschreiben und nicht per using importieren:
// Eindeutig
[UIHint(UiEditor.Basis.DropdownList)]
[AdditionalMetadata(UiMetadata.Basis.DropdownListSelection, nameof(Laender))]
// Mehrdeutig: mit beiden using-Zeilen meldet der Compiler CS0104
using UiEditor;
using UiMetadata;
[UIHint(Basis.DropdownList)]
Mit nur einer using-Zeile kompiliert Basis.X zwar, beim Lesen ist aber nicht mehr zu erkennen, ob ein Template-Name oder ein Schlüssel gemeint ist.
Wo die Einstiege liegen
Alle drei liegen in den Validierungs-Paketen und nicht bei den Templates. So kann eine Bibliothek mit ViewModels sie verwenden, ohne die Razor Class Library zu referenzieren.
| Paket | Einstiege |
|---|---|
FMH.Komponente.Basis.Validierung |
UiDisplay.Basis, UiEditor.Basis, UiMetadata.Basis |
FMH.Komponente.FileUpload.Validierung |
UiEditor.FileUpload, UiMetadata.FileUpload |
FMH.Komponente.Kompetenzen.Validierung |
UiEditor.Kompetenzen |
FMH.Komponente.RichText.Validierung |
UiEditor.RichText |
RichText und Kompetenzen haben keine eigenen Schlüssel. Der Richtext-Editor liest UiMetadata.Basis.ShowLabel aus FMH.Komponente.Basis.Validierung.