Delen via


binding van kernformulieren Blazor ASP.NET

Opmerking

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 10-versie van dit artikel voor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 10-versie van dit artikel voor de huidige release.

In dit artikel wordt uitgelegd hoe u binding gebruikt in Blazor formulieren.

EditForm / EditContext Model

Een EditForm maakt een EditContext op basis van het toegewezen object als trapsgewijze waarde voor andere onderdelen in het formulier. De EditContext metagegevens over het bewerkingsproces worden bijgehouden, inclusief welke formuliervelden zijn gewijzigd en de huidige validatieberichten. Door aan een EditForm.Model of een EditForm.EditContext toe te wijzen, kan een formulier aan gegevens worden gekoppeld.

Modelbinding

Toewijzing aan EditForm.Model:

<EditForm ... Model="Model" ...>
    ...
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();
}
<EditForm ... Model="Model" ...>
    ...
</EditForm>

@code {
    public Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();
}

Opmerking

De meeste formuliermodelvoorbeelden van dit artikel binden formulieren aan C#- eigenschappen, maar C#-veldbinding wordt ook ondersteund.

Contextbinding

Toewijzing aan EditForm.EditContext:

<EditForm ... EditContext="editContext" ...>
    ...
</EditForm>

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
    }
}
<EditForm ... EditContext="editContext" ...>
    ...
</EditForm>

@code {
    private EditContext? editContext;

    public Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
    }
}

Wijs een EditContextof een Model toe aan een EditForm. Als beide zijn toegewezen, treedt er een runtimefout op.

Ondersteunde typen

Bindingsteunen

  • Primitieve typen
  • Collections
  • Complexe typen
  • Recursieve typen
  • Typen met constructors
  • Enums

U kunt ook de [DataMember] en [IgnoreDataMember] kenmerken gebruiken om modelbinding aan te passen. Gebruik deze kenmerken om de naam van eigenschappen te wijzigen, eigenschappen te negeren en eigenschappen te markeren zoals vereist.

Aanvullende bindingsopties

Aanvullende opties voor modelbinding zijn beschikbaar vanuit RazorComponentsServiceOptions wanneer AddRazorComponents wordt aangeroepen.

Hieronder ziet u de standaardwaarden die door het framework zijn toegewezen:

builder.Services.AddRazorComponents(options =>
{
    options.FormMappingUseCurrentCulture = true;
    options.MaxFormMappingCollectionSize = 1024;
    options.MaxFormMappingErrorCount = 200;
    options.MaxFormMappingKeySize = 1024 * 2;
    options.MaxFormMappingRecursionDepth = 64;
}).AddInteractiveServerComponents();

Formuliernamen

Gebruik de FormName parameter om een formuliernaam toe te wijzen. Formuliernamen moeten uniek zijn om modelgegevens te binden. Het volgende formulier heeft de naam RomulanAle:

<EditForm ... FormName="RomulanAle" ...>
    ...
</EditForm>

Geef een formuliernaam op:

  • Is vereist voor alle formulieren die worden verzonden door statisch gerenderde onderdelen aan de serverzijde.
  • Is niet vereist voor formulieren die worden verzonden door interactief gerenderde onderdelen, waaronder formulieren in Blazor WebAssembly apps en onderdelen met een interactieve weergavemodus. We raden u echter aan een unieke formuliernaam op te geven voor elk formulier om fouten bij het plaatsen van runtimeformulieren te voorkomen als interactiviteit ooit voor een formulier wordt verwijderd.

De formuliernaam wordt alleen gecontroleerd wanneer het formulier wordt gepost op een eindpunt als een traditionele HTTP POST-aanvraag vanuit een statisch gerenderd onderdeel aan de serverzijde. Het framework genereert geen uitzondering op het punt van het weergeven van een formulier, maar alleen op het punt dat een HTTP POST binnenkomt en geen formuliernaam opgeeft.

Er is een niet-benoemde formulierbereik (lege tekenreeks) boven de hoofdcomponent van de app, wat volstaat wanneer er geen formuliernaamconflicten binnen de app zijn. Als er sprake is van conflicten tussen formuliernamen, zoals wanneer een formulier uit een bibliotheek wordt opgenomen en u geen controle hebt over de formuliernaam die wordt gebruikt door de ontwikkelaar van de bibliotheek, geeft u een formuliernaambereik op met het onderdeel in het FormMappingScopeBlazor Web Apphoofdproject.

In het volgende voorbeeld heeft het HelloFormFromLibrary onderdeel een formulier met de naam Hello en bevindt zich in een bibliotheek.

HelloFormFromLibrary.razor:

<EditForm FormName="Hello" Model="this" OnSubmit="Submit">
    <InputText @bind-Value="Name" />
    <button type="submit">Submit</button>
</EditForm>

@if (submitted)
{
    <p>Hello @Name from the library's form!</p>
}

@code {
    bool submitted = false;

    [SupplyParameterFromForm]
    private string? Name { get; set; }

    private void Submit() => submitted = true;
}

Het volgende NamedFormsWithScope onderdeel maakt gebruik van het onderdeel van HelloFormFromLibrary de bibliotheek en heeft ook een formulier met de naam Hello. De FormMappingScope bereiknaam van het onderdeel is ParentContext bedoeld voor formulieren die door het HelloFormFromLibrary onderdeel worden geleverd. Hoewel beide formulieren in dit voorbeeld de formuliernaam (Hello) hebben, komen de formuliernamen niet overeen en worden gebeurtenissen doorgestuurd naar het juiste formulier voor POST-gebeurtenissen.

NamedFormsWithScope.razor:

@page "/named-forms-with-scope"

<div>Hello form from a library</div>

<FormMappingScope Name="ParentContext">
    <HelloFormFromLibrary />
</FormMappingScope>

<div>Hello form using the same form name</div>

<EditForm FormName="Hello" Model="this" OnSubmit="Submit">
    <InputText @bind-Value="Name" />
    <button type="submit">Submit</button>
</EditForm>

@if (submitted)
{
    <p>Hello @Name from the app form!</p>
}

@code {
    bool submitted = false;

    [SupplyParameterFromForm]
    private string? Name { get; set; }

    private void Submit() => submitted = true;
}

Geef een parameter op uit het formulier ([SupplyParameterFromForm])

Het [SupplyParameterFromForm] kenmerk geeft aan dat de waarde van de bijbehorende eigenschap moet worden opgegeven uit de formuliergegevens voor het formulier. Gegevens in de aanvraag die overeenkomen met de naam van de eigenschap, zijn gebonden aan de eigenschap. Invoer gebaseerd op InputBase<TValue> genereert formulierwaardenamen die overeenkomen met de namen die Blazor gebruikt voor modelbinding. In tegenstelling tot componentparameter-eigenschappen ([Parameter]) hoeven eigenschappen met [SupplyParameterFromForm]-annotaties niet als public te worden gemarkeerd.

U kunt de volgende parameters voor formulierbinding opgeven voor het [SupplyParameterFromForm] kenmerk:

  • Name: haalt de naam voor de parameter op of stelt deze in. De naam wordt gebruikt om het voorvoegsel te bepalen dat moet worden gebruikt om overeen te komen met de formuliergegevens en om te bepalen of de waarde moet worden gebonden.
  • FormName: Haalt de naam voor de handler op of stelt deze in. De naam wordt gebruikt om de parameter aan het formulier te koppelen op basis van de formuliernaam, om te bepalen of de waarde gebonden moet worden.

In het volgende voorbeeld worden twee formulieren onafhankelijk gekoppeld aan hun modellen door de naam van het formulier.

Starship6.razor:

@page "/starship-6"
@inject ILogger<Starship6> Logger

<EditForm Model="Model1" OnSubmit="Submit1" FormName="Holodeck1">
    <div>
        <label>
            Holodeck 1 Identifier: 
            <InputText @bind-Value="Model1!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

<EditForm Model="Model2" OnSubmit="Submit2" FormName="Holodeck2">
    <div>
        <label>
            Holodeck 2 Identifier: 
            <InputText @bind-Value="Model2!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm(FormName = "Holodeck1")]
    private Holodeck? Model1 { get; set; }

    [SupplyParameterFromForm(FormName = "Holodeck2")]
    private Holodeck? Model2 { get; set; }

    protected override void OnInitialized()
    {
        Model1 ??= new();
        Model2 ??= new();
    }

    private void Submit1() => Logger.LogInformation("Submit1: Id={Id}", Model1?.Id);

    private void Submit2() => Logger.LogInformation("Submit2: Id={Id}", Model2?.Id);

    public class Holodeck
    {
        public string? Id { get; set; }
    }
}
@page "/starship-6"
@inject ILogger<Starship6> Logger

<EditForm Model="Model1" OnSubmit="Submit1" FormName="Holodeck1">
    <div>
        <label>
            Holodeck 1 Identifier: 
            <InputText @bind-Value="Model1!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

<EditForm Model="Model2" OnSubmit="Submit2" FormName="Holodeck2">
    <div>
        <label>
            Holodeck 2 Identifier: 
            <InputText @bind-Value="Model2!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm(FormName = "Holodeck1")]
    private Holodeck? Model1 { get; set; }

    [SupplyParameterFromForm(FormName = "Holodeck2")]
    private Holodeck? Model2 { get; set; }

    protected override void OnInitialized()
    {
        Model1 ??= new();
        Model2 ??= new();
    }

    private void Submit1() => Logger.LogInformation("Submit1: Id={Id}", Model1?.Id);

    private void Submit2() => Logger.LogInformation("Submit2: Id={Id}", Model2?.Id);

    public class Holodeck
    {
        public string? Id { get; set; }
    }
}

Formulieren nesten en koppelen

Deze richtlijnen laten zien hoe u subformulieren kunt nesten en binden.

De volgende scheepsdetailsklasse (ShipDetails) bevat een beschrijving en lengte voor een subformulier.

ShipDetails.cs:

namespace BlazorSample;

public class ShipDetails
{
    public string? Description { get; set; }
    public int? Length { get; set; }
}
namespace BlazorSample;

public class ShipDetails
{
    public string? Description { get; set; }
    public int? Length { get; set; }
}

De volgende Ship klasse noemt een id (Id) en bevat de verzendgegevens.

Ship.cs:

namespace BlazorSample
{
    public class Ship
    {
        public string? Id { get; set; }
        public ShipDetails Details { get; set; } = new();
    }
}
namespace BlazorSample
{
    public class Ship
    {
        public string? Id { get; set; }
        public ShipDetails Details { get; set; } = new();
    }
}

Het volgende subformulier wordt gebruikt voor het bewerken van waarden van het ShipDetails type. Dit wordt geïmplementeerd door bovenaan het onderdeel over te Editor<T> nemen. Editor<T> zorgt ervoor dat het onderliggende onderdeel de juiste formulierveldnamen genereert op basis van het model (T), waarbij T in het volgende voorbeeld ShipDetails is.

StarshipSubform.razor:

@inherits Editor<ShipDetails>

<div>
    <label>
        Description: 
        <InputText @bind-Value="Value!.Description" />
    </label>
</div>
<div>
    <label>
        Length: 
        <InputNumber @bind-Value="Value!.Length" />
    </label>
</div>
@inherits Editor<ShipDetails>

<div>
    <label>
        Description: 
        <InputText @bind-Value="Value!.Description" />
    </label>
</div>
<div>
    <label>
        Length: 
        <InputNumber @bind-Value="Value!.Length" />
    </label>
</div>

Het hoofdformulier is gebonden aan de Ship klasse. Het StarshipSubform onderdeel wordt gebruikt om verzendgegevens te bewerken, gebonden als Model!.Details.

Starship7.razor:

@page "/starship-7"
@inject ILogger<Starship7> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship7">
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <StarshipSubform @bind-Value="Model!.Details" />
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Ship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => 
        Logger.LogInformation("Id = {Id} Desc = {Description} Length = {Length}",
            Model?.Id, Model?.Details?.Description, Model?.Details?.Length);
}
@page "/starship-7"
@inject ILogger<Starship7> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship7">
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <StarshipSubform @bind-Value="Model!.Details" />
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Ship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => 
        Logger.LogInformation("Id = {Id} Desc = {Description} Length = {Length}",
            Model?.Id, Model?.Details?.Description, Model?.Details?.Length);
}

Formuliergegevens initialiseren met statische SSR

Wanneer een component statische SSR aanneemt, worden de OnInitialized{Async} levenscyclusmethode en de OnParametersSet{Async} levenscyclusmethode geactiveerd wanneer het component aanvankelijk wordt weergegeven en bij elke formulier-POST naar de server. Als u formuliermodelwaarden wilt initialiseren, controleert u of het model al gegevens bevat voordat u nieuwe modelwaarden OnParametersSet{Async}toewijst, zoals in het volgende voorbeeld wordt gedemonstreert.

StarshipInit.razor:

@page "/starship-init"
@inject ILogger<StarshipInit> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="StarshipInit">
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    protected override void OnParametersSet()
    {
        if (Model!.Id == default)
        {
            LoadData();
        }
    }

    private void LoadData()
    {
        Model!.Id = "Set by LoadData";
    }

    private void Submit()
    {
        Logger.LogInformation("Id = {Id}", Model?.Id);
    }

    public class Starship
    {
        public string? Id { get; set; }
    }
}

Geavanceerde foutscenario's voor formulierveldtoewijzing

Het framework instantieert en vult het FormMappingContext voor een formulier in. Dit is de context die is gekoppeld aan de toewijzingsbewerking van een bepaald formulier. Elk toewijzingsbereik (gedefinieerd door een FormMappingScope component) instantieert FormMappingContext. Telkens wanneer een [SupplyParameterFromForm] de context om een waarde vraagt, vult het framework de FormMappingContext met de opgevraagde waarde en eventuele koppelingsfouten.

Ontwikkelaars worden niet verwacht om rechtstreeks met FormMappingContext te werken, omdat het voornamelijk een gegevensbron is voor InputBase<TValue>, EditContext en andere interne implementaties om toewijzingsfouten als validatiefouten te tonen. In geavanceerde aangepaste scenario's hebben ontwikkelaars rechtstreeks toegang tot FormMappingContext als een [CascadingParameter] om aangepaste code te schrijven die de geprobeerde waarden en toewijzingsfouten verwerkt.

Aangepaste invoeronderdelen

Voor aangepaste scenario's voor invoerverwerking demonstreren de volgende subsecties aangepaste invoeronderdelen:

We raden u aan om uw aangepaste invoeronderdelen af te leiden van InputBase<TValue> , tenzij specifieke vereisten u dit verhinderen. De InputBase<TValue> klasse wordt actief onderhouden door het ASP.NET Core-team, zodat deze up-to-date blijft met de nieuwste Blazor functies en frameworkwijzigingen.

Invoercomponent op basis van InputBase<T>

Het volgende voorbeeldonderdeel:

  • Neemt over van InputBase<TValue>. Onderdelen die erven van InputBase<TValue> moeten worden gebruikt in een Blazor formulier (EditForm).
  • Neemt booleaanse invoer uit een selectievakje.
  • Hiermee stelt u de achtergrondkleur van de container <div> in op basis van de status van het selectievakje, wat optreedt wanneer de AfterChange methode wordt uitgevoerd na binding (@bind:after).
  • Is vereist om de methode van TryParseValueFromString de basisklasse te overschrijven, maar verwerkt geen invoergegevens voor tekenreeksen omdat een selectievakje geen tekenreeksgegevens levert. Voorbeelden van implementaties van TryParseValueFromString andere typen invoeronderdelen die tekenreeksinvoer verwerken, zijn beschikbaar in de ASP.NET Core-referentiebron.

Opmerking

Documentatiekoppelingen naar .NET-referentiebron laden meestal de standaardbranch van de opslagplaats, die de huidige ontwikkeling vertegenwoordigt voor de volgende release van .NET. Als u een tag voor een specifieke release wilt selecteren, gebruikt u de Switch branches of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

EngineeringApprovalInputDerived.razor:

@using System.Diagnostics.CodeAnalysis
@inherits InputBase<bool>

<div class="@divCssClass">
    <label>
        Engineering Approval:
        <input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass" 
            type="checkbox" />
    </label>
</div>

@code {
    private string? divCssClass;

    private void AfterChange()
    {
        divCssClass = CurrentValue ? "bg-success text-white" : null;
    }

    protected override bool TryParseValueFromString(
        string? value, out bool result, 
        [NotNullWhen(false)] out string? validationErrorMessage)
            => throw new NotSupportedException(
                "This component does not parse string inputs. " +
                $"Bind to the '{nameof(CurrentValue)}' property, " +
                $"not '{nameof(CurrentValueAsString)}'.");
}

Als u het voorgaande onderdeel in het voorbeeldformulier voor ruimteschepen (Starship3.razor/Starship.cs) wilt gebruiken, vervangt u het <div> blok voor het veld voor technische goedkeuring door een EngineeringApprovalInputDerived onderdeelelement dat is gebonden aan de eigenschap IsValidatedDesign van het model.

- <div>
-     <label>
-         Engineering Approval: 
-         <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
-     </label>
- </div>
+ <EngineeringApprovalInputDerived @bind-Value="Model!.IsValidatedDesign" />

Als het onderdeel dat overerft van InputBase<TValue>, ooit statisch wordt weergegeven, moet de InputBase<TValue>.NameAttributeValue eigenschap aan het name kenmerk van de <input> elementen toegewezen worden.

<input @bind="CurrentValue" @bind:after="AfterChange" class="@CssClass"
    type="checkbox" name="@NameAttributeValue" />

De voorgaande toewijzing is niet nodig als het onderdeel gegarandeerd interactief wordt weergegeven.

Invoeronderdeel met volledig beheer voor ontwikkelaars

Het volgende voorbeeldonderdeel:

  • Neemt niet over van InputBase<TValue>. Het onderdeel heeft volledige controle over invoerverwerking, inclusief binding, callbacks en validatie. Het onderdeel kan binnen of buiten een Blazor formulier (EditForm) worden gebruikt.
  • Neemt booleaanse invoer uit een selectievakje.
  • Hiermee wijzigt u de achtergrondkleur als het selectievakje is ingeschakeld.

Code in het onderdeel omvat:

  • De Value eigenschap wordt gebruikt met een binding in twee richtingen om de waarde van de invoer op te halen of in te stellen. ValueChanged is de callback waarmee de afhankelijke waarde wordt bijgewerkt.

  • Bij gebruik in een Blazor formulier:

    • Dit EditContext is een trapsgewijze waarde.
    • fieldCssClass stijlt het veld op basis van het resultaat van EditContext validatie.
    • ValueExpression is een expressie (Expression<Func<T>>) die is toegewezen door het framework waarmee de afhankelijke waarde wordt geïdentificeerd.
    • FieldIdentifier identificeert uniek één veld dat kan worden bewerkt, meestal overeenkomend met een modeleigenschap. De veld-id wordt gemaakt met de expressie waarmee de afhankelijke waarde (ValueExpression) wordt geïdentificeerd.
  • In de OnChange event handler:

    • De waarde van de invoer van het selectievakje wordt verkregen van InputFileChangeEventArgs.
    • De achtergrondkleur en tekstkleur van het containerelement <div> worden ingesteld.
    • EventCallback.InvokeAsync roept de afgevaardigde aan die aan de binding is gekoppeld en verstuurt een eventmelding naar gebruikers dat de waarde is gewijzigd.
    • Als de component wordt gebruikt in een EditForm (de EditContext eigenschap niet null), wordt EditContext.NotifyFieldChanged aangeroepen om de validatie te starten.

EngineeringApprovalInputStandalone.razor:

@using System.Globalization
@using System.Linq.Expressions

<div class="@divCssClass">
    <label>
        Engineering Approval:
        <input class="@fieldCssClass" @onchange="OnChange" type="checkbox" 
            value="@Value" />
    </label>
</div>

@code {
    private string? divCssClass;
    private FieldIdentifier fieldIdentifier;
    private string? fieldCssClass => EditContext?.FieldCssClass(fieldIdentifier);

    [CascadingParameter]
    private EditContext? EditContext { get; set; }

    [Parameter]
    public bool? Value { get; set; }

    [Parameter]
    public EventCallback<bool> ValueChanged { get; set; }

    [Parameter]
    public Expression<Func<bool>>? ValueExpression { get; set; }

    protected override void OnInitialized()
    {
        fieldIdentifier = FieldIdentifier.Create(ValueExpression!);
    }

    private async Task OnChange(ChangeEventArgs args)
    {
        BindConverter.TryConvertToBool(args.Value, CultureInfo.CurrentCulture, 
            out var value);

        divCssClass = value ? "bg-success text-white" : null;

        await ValueChanged.InvokeAsync(value);
        EditContext?.NotifyFieldChanged(fieldIdentifier);
    }
}

Als u het voorgaande onderdeel in het voorbeeldformulier starship (Starship3.razor/Starship.cs) wilt gebruiken, vervangt u het <div> blok voor het veld voor technische goedkeuring door een EngineeringApprovalInputStandalone onderdeelexemplaren dat zijn gebonden aan de van het model's IsValidatedDesign eigenschap:

- <div>
-     <label>
-         Engineering Approval: 
-         <InputCheckbox @bind-Value="Model!.IsValidatedDesign" />
-     </label>
- </div>
+ <EngineeringApprovalInputStandalone @bind-Value="Model!.IsValidatedDesign" />

Het EngineeringApprovalInputStandalone onderdeel is ook functioneel buiten een EditForm:

<EngineeringApprovalInputStandalone @bind-Value="ValidDesign" />

<div>
    <b>ValidDesign:</b> @ValidDesign
</div>

@code {
    private bool ValidDesign { get; set; }
}

Radioknopjes

Het voorbeeld in deze sectie is gebaseerd op het Starfleet Starship Database formulier (Starship3 onderdeel) van de sectie Voorbeeldformulier van dit artikel.

Voeg de volgende enum typen toe aan de app. Maak een nieuw bestand om ze op te slaan of toe te voegen aan het Starship.cs bestand.

public class ComponentEnums
{
    public enum Manufacturer { SpaceX, NASA, ULA, VirginGalactic, Unknown }
    public enum Color { ImperialRed, SpacecruiserGreen, StarshipBlue, VoyagerOrange }
    public enum Engine { Ion, Plasma, Fusion, Warp }
}

Maak de ComponentEnums klasse toegankelijk voor het volgende:

  • Starship model in Starship.cs (bijvoorbeeld using static ComponentEnums;).
  • Starfleet Starship Database formulier () (Starship3.razorbijvoorbeeld @using static ComponentEnums).

Gebruik InputRadio<TValue> componenten met de InputRadioGroup<TValue> component om een radioknopgroep te maken. In het volgende voorbeeld worden eigenschappen toegevoegd aan het Starship model dat wordt beschreven in de sectie Voorbeeldformulier van het artikel Invoeronderdelen :

[Required]
[Range(typeof(Manufacturer), nameof(Manufacturer.SpaceX), 
    nameof(Manufacturer.VirginGalactic), ErrorMessage = "Pick a manufacturer.")]
public Manufacturer Manufacturer { get; set; } = Manufacturer.Unknown;

[Required, EnumDataType(typeof(Color))]
public Color? Color { get; set; } = null;

[Required, EnumDataType(typeof(Engine))]
public Engine? Engine { get; set; } = null;

Werk het Starfleet Starship Database formulier (Starship3 onderdeel) van de sectie Voorbeeldformulier van het artikel Invoeronderdelen bij. Voeg de onderdelen toe die u wilt produceren:

  • Een radioknopgroep voor de scheepsfabrikant.
  • Een geneste keuzerondjesgroep voor motor- en schipkleur.

Opmerking

Geneste keuzerondjes worden niet vaak gebruikt in formulieren, omdat ze kunnen resulteren in een niet-georganiseerde indeling van formulierbesturingselementen die gebruikers kunnen verwarren. Er zijn echter gevallen waarin ze zinvol zijn in UI-ontwerp, zoals in het volgende voorbeeld dat aanbevelingen voor de twee gebruikersinvoeren, scheepsmotor en scheepskleur, koppelt. Eén engine en één kleur zijn vereist voor de validatie van het formulier. De indeling van het formulier maakt gebruik van geneste InputRadioGroup<TValue>s om aanbevelingen voor motor en kleur te koppelen. De gebruiker kan echter elke motor combineren met elke kleur om het formulier te verzenden.

Opmerking

Zorg ervoor dat de ComponentEnums klasse beschikbaar is voor het onderdeel voor het volgende voorbeeld:

@using static ComponentEnums
<fieldset>
    <legend>Manufacturer</legend>
    <InputRadioGroup @bind-Value="Model!.Manufacturer">
        @foreach (var manufacturer in Enum.GetValues<Manufacturer>())
        {
            <div>
                <label>
                    <InputRadio Value="manufacturer" />
                    @manufacturer
                </label>
            </div>
        }
    </InputRadioGroup>
</fieldset>

<fieldset>
    <legend>Engine and Color</legend>
    <p>
        Engine and color pairs are recommended, but any
        combination of engine and color is allowed.
    </p>
    <InputRadioGroup Name="engine" @bind-Value="Model!.Engine">
        <InputRadioGroup Name="color" @bind-Value="Model!.Color">
            <div style="margin-bottom:5px">
                <div>
                    <label>
                        <InputRadio Name="engine" Value="Engine.Ion" />
                        Ion
                    </label>
                </div>
                <div>
                    <label>
                        <InputRadio Name="color" Value="Color.ImperialRed" />
                        Imperial Red
                    </label>
                </div>
            </div>
            <div style="margin-bottom:5px">
                <div>
                    <label>
                        <InputRadio Name="engine" Value="Engine.Plasma" />
                        Plasma
                    </label>
                </div>
                <div>
                    <label>
                        <InputRadio Name="color" Value="Color.SpacecruiserGreen" />
                        Spacecruiser Green
                    </label>
                </div>
            </div>
            <div style="margin-bottom:5px">
                <div>
                    <label>
                        <InputRadio Name="engine" Value="Engine.Fusion" />
                        Fusion
                    </label>
                </div>
                <div>
                    <label>
                        <InputRadio Name="color" Value="Color.StarshipBlue" />
                        Starship Blue
                    </label>
                </div>
            </div>
            <div style="margin-bottom:5px">
                <div>
                    <label>
                        <InputRadio Name="engine" Value="Engine.Warp" />
                        Warp
                    </label>
                </div>
                <div>
                    <label>
                        <InputRadio Name="color" Value="Color.VoyagerOrange" />
                        Voyager Orange
                    </label>
                </div>
            </div>
        </InputRadioGroup>
    </InputRadioGroup>
</fieldset>

Opmerking

Als Name wordt weggelaten, worden InputRadio<TValue>-onderdelen gegroepeerd op hun meest recente bovenliggende element.

Als u de voorgaande Razor markeringen hebt geïmplementeerd in het onderdeel van het Starship3gedeelte Voorbeeldformulier van het artikel Invoeronderdelen , werkt u de logboekregistratie voor de Submit methode bij:

Logger.LogInformation("Id = {Id} Description = {Description} " +
    "Classification = {Classification} MaximumAccommodation = " +
    "{MaximumAccommodation} IsValidatedDesign = " +
    "{IsValidatedDesign} ProductionDate = {ProductionDate} " +
    "Manufacturer = {Manufacturer}, Engine = {Engine}, " +
    "Color = {Color}",
    Model?.Id, Model?.Description, Model?.Classification,
    Model?.MaximumAccommodation, Model?.IsValidatedDesign,
    Model?.ProductionDate, Model?.Manufacturer, Model?.Engine, 
    Model?.Color);

Wanneer u met radioknoppen in een formulier werkt, wordt gegevensbinding op een andere manier verwerkt dan bij andere elementen, omdat radioknoppen als een groep worden geëvalueerd. De waarde van elk keuzerondje is vast, maar de waarde van de keuzerondjesgroep is de waarde van het geselecteerde keuzerondje. In het volgende voorbeeld ziet u hoe u:

  • Afhandelen van gegevensbinding voor een radioknopgroep.
  • Ondersteuning voor validatie met behulp van een aangepast InputRadio<TValue> onderdeel.

InputRadio.razor:

@using System.Globalization
@inherits InputBase<TValue>
@typeparam TValue

<input @attributes="AdditionalAttributes" type="radio" value="@SelectedValue" 
       checked="@(SelectedValue.Equals(Value))" @onchange="OnChange" />

@code {
    [Parameter]
    public TValue SelectedValue { get; set; }

    private void OnChange(ChangeEventArgs args)
    {
        CurrentValueAsString = args.Value.ToString();
    }

    protected override bool TryParseValueFromString(string value, 
        out TValue result, out string errorMessage)
    {
        var success = BindConverter.TryConvertTo<TValue>(
            value, CultureInfo.CurrentCulture, out var parsedValue);
        if (success)
        {
            result = parsedValue;
            errorMessage = null;

            return true;
        }
        else
        {
            result = default;
            errorMessage = "The field isn't valid.";

            return false;
        }
    }
}

Zie de volgende artikelen voor meer informatie over algemene typeparameters (@typeparam:

Gebruik het volgende voorbeeldmodel.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

namespace BlazorServer80
{
    public class Model
    {
        [Range(1, 5)]
        public int Rating { get; set; }
    }
}

In het volgende RadioButtonExample onderdeel wordt het voorgaande InputRadio onderdeel gebruikt om een beoordeling van de gebruiker te verkrijgen en te valideren:

RadioButtonExample.razor:

@page "/radio-button-example"
@using System.ComponentModel.DataAnnotations
@using Microsoft.Extensions.Logging
@inject ILogger<RadioButtonExample> Logger

<h1>Radio Button Example</h1>

<EditForm Model="Model" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    @for (int i = 1; i <= 5; i++)
    {
        <div>
            <label>
                <InputRadio name="rate" SelectedValue="i" 
                    @bind-Value="Model.Rating" />
                @i
            </label>
        </div>
    }

    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

<div>@Model.Rating</div>

@code {
    public StarshipModel Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");
    }
}