Dela via


ASP.NET Core Blazor formulärbindning

Not

Det här är inte den senaste versionen av den här artikeln. Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. Den aktuella versionen av den här artikeln finns i .NET 9-versionen .

Viktig

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.

Den här artikeln beskriver hur du använder bindning i Blazor formulär.

EditForm / EditContext modell

En EditForm skapar en EditContext baserat på det tilldelade objektet som ett kaskadvärde för andra komponenter i formuläret. EditContext spårar metadata om redigeringsprocessen, inklusive vilka formulärfält som har ändrats och de aktuella valideringsmeddelandena. Tilldelning till antingen en EditForm.Model eller en EditForm.EditContext kan binda ett formulär till data.

Modellbindning

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

Not

De flesta av den här artikelns formulärmodellexempel binder formulär till C# egenskaper, men C#-fältbindning stöds också.

Kontextbindning

Tilldelning till 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);
    }
}

Tilldela antingen en EditContexteller en Model till en EditForm. Om båda tilldelas genereras ett körningsfel.

Typer som stöds

Bindningsstöd:

  • Primitiva typer
  • Samlingar
  • Komplexa typer
  • Rekursiva typer
  • Typer med konstruktorer
  • Uppräkningar

Du kan också använda attributen [DataMember] och [IgnoreDataMember] för att anpassa modellbindningen. Använd dessa attribut för att byta namn på egenskaper, ignorera egenskaper och markera egenskaper efter behov.

Ytterligare bindningsalternativ

Ytterligare alternativ för modellbindning är tillgängliga från RazorComponentsServiceOptions när du anropar AddRazorComponents:

Följande visar standardvärdena som tilldelats av ramverket:

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

Formulärnamn

Använd parametern FormName för att tilldela ett formulärnamn. Formulärnamn måste vara unika för att binda modelldata. Följande formulär heter RomulanAle:

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

Anger ett formulärnamn:

  • Krävs för alla formulär som skickas av statiskt renderade komponenter på serversidan.
  • Krävs inte för formulär som skickas av interaktivt renderade komponenter, som innehåller formulär i Blazor WebAssembly appar och komponenter med ett interaktivt återgivningsläge. Vi rekommenderar dock att du anger ett unikt formulärnamn för varje formulär för att förhindra runtime-formulärpubliceringsfel om interaktivitet någonsin tas bort för ett formulär.

Formulärnamnet kontrolleras endast när formuläret publiceras till en slutpunkt som en traditionell HTTP POST-begäran från en statiskt renderad komponent på serversidan. Ramverket utlöser inte ett undantag vid tidpunkten för återgivning av ett formulär, men bara vid den tidpunkt då en HTTP POST anländer och inte anger ett formulärnamn.

Det finns ett namnlöst (tom sträng) formuläromfång ovanför appens rotkomponent, vilket räcker när det inte finns några kollisioner med formulärnamn i appen. Om kollisioner med formulärnamn är möjliga, till exempel när du inkluderar ett formulär från ett bibliotek och du inte har någon kontroll över det formulärnamn som används av bibliotekets utvecklare, anger du ett formulärnamnsomfång med FormMappingScope komponenten i Blazor Web Apphuvudprojekt.

I följande exempel har komponenten HelloFormFromLibrary ett formulär med namnet Hello och finns i ett bibliotek.

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

Följande NamedFormsWithScope komponent använder bibliotekets HelloFormFromLibrary komponent och har även ett formulär med namnet Hello. FormMappingScope-komponentens omfångsnamn är ParentContext för alla formulär som tillhandahålls av HelloFormFromLibrary komponenten. Även om båda formulären i det här exemplet har formulärnamnet (Hello), kolliderar inte formulärnamnen och händelserna dirigeras till rätt formulär för POST-formulärhändelser.

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

Ange en parameter från formuläret ([SupplyParameterFromForm])

Attributet [SupplyParameterFromForm] anger att värdet för den associerade egenskapen ska anges från formulärdata för formuläret. Data i begäran som matchar namnet på egenskapen är bundna till egenskapen. Indata baserade på InputBase<TValue> genererar formulärvärdenamn som matchar namnen Blazor använder för modellbindning. Till skillnad från egenskaper för komponentparameter ([Parameter]) behöver egenskaper som kommenterats med [SupplyParameterFromForm] inte markeras public.

Du kan ange följande formulärbindningsparametrar för attributet [SupplyParameterFromForm]:

  • Name: Hämtar eller anger namnet på parametern. Namnet används för att fastställa prefixet som ska användas för att matcha formulärdata och avgöra om värdet måste bindas eller inte.
  • FormName: Hämtar eller anger namnet på hanteraren. Namnet används för att matcha parametern med formuläret efter formulärnamn för att avgöra om värdet måste bindas eller inte.

Följande exempel binder oberoende två formulär till sina modeller med hjälp av formulärnamnet.

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

Kapsla och binda formulär

Följande vägledning visar hur du kapslar och binder underordnade formulär.

Följande leveransinformationsklass (ShipDetails) innehåller en beskrivning och längd för ett underformulär.

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

Följande Ship klassificerar en identifierare (Id) och innehåller leveransinformationen.

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

Följande underformulär används för att redigera värden av den ShipDetails typen. Detta implementeras genom att ärva Editor<T> överst i komponenten. Editor<T> ser till att den underordnade komponenten genererar rätt formulärfältnamn baserat på modellen (T), där T i följande exempel är ShipDetails.

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>

Huvudformuläret är bundet till klassen Ship. Komponenten StarshipSubform används för att redigera leveransinformation, bunden som 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);
}

Initiera formulärdata med statisk SSR

När en komponent använder statisk SSR livscykelmetod och livscykelmetod ut när komponenten ursprungligen återges och på varje postformulär till servern. Om du vill initiera formulärmodellvärden kontrollerar du om modellen redan har data innan du tilldelar nya modellvärden i OnParametersSet{Async}, vilket visas i följande exempel.

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

Felscenarier för avancerad formulärmappning

Ramverket instansierar och fyller i FormMappingContext för ett formulär, vilket är kontexten som är associerad med ett visst formulärs mappningsåtgärd. Varje mappningsomfång (definierat av en FormMappingScope komponent) instansierar FormMappingContext. Varje gång en [SupplyParameterFromForm] frågar kontexten om ett värde fyller ramverket FormMappingContext med det förfrågade värdet och eventuella mappningsfel.

Utvecklare förväntas inte interagera med FormMappingContext direkt, eftersom det främst är en datakälla för InputBase<TValue>, EditContextoch andra interna implementeringar för att visa mappningsfel som valideringsfel. I avancerade anpassade scenarier kan utvecklare komma åt FormMappingContext direkt som en [CascadingParameter] för att skriva anpassad kod som hanterar de försökte värden och mappningsfelen.

Anpassade indatakomponenter

För scenarier för anpassad indatabearbetning visar följande underavsnitt anpassade indatakomponenter:

Vi rekommenderar att du härleder dina anpassade indatakomponenter från InputBase<TValue> såvida inte specifika krav hindrar dig från att göra det. Klassen InputBase<TValue> underhålls aktivt av ASP.NET Core-teamet, vilket säkerställer att den förblir up-touppdaterad med de senaste funktionerna och ändringar i Blazor-ramverket.

Indatakomponent baserad på InputBase<T>

Följande exempelkomponent:

  • Ärver från InputBase<TValue>. Komponenter som ärver från InputBase<TValue> måste användas i ett Blazor formulär (EditForm).
  • Tar booleska indata från en kryssruta.
  • Anger bakgrundsfärgen för containern <div> baserat på kryssrutans tillstånd, vilket inträffar när metoden AfterChange körs efter bindningen (@bind:after).
  • Krävs för att åsidosätta basklassens TryParseValueFromString-metod men bearbetar inte strängindata eftersom en kryssruta inte innehåller strängdata. Exempelimplementeringar av TryParseValueFromString för andra typer av indatakomponenter som bearbetar strängindata finns i ASP.NET Core-referenskällan.

Not

Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Växla grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).

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)}'.");
}

Om du vill använda föregående komponent i exempelformuläret rymdskepp (Starship3.razor/Starship.cs)ersätter du <div>-blocket för fältet för tekniskt godkännande med en EngineeringApprovalInputDerived komponentinstans som är bunden till modellens egenskap IsValidatedDesign:

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

Om komponenten som ärver från InputBase<TValue> någon gång renderas statiskt, bör du tilldela egenskapen InputBase<TValue>.NameAttributeValue till attributet name för <input>-elementen.

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

Tidigare tilldelning är inte nödvändig om komponenten garanteras att alltid renderas interaktivt.

Indatakomponent med fullständig utvecklarkontroll

Följande exempelkomponent:

  • Ärver inte från InputBase<TValue>. Komponenten tar fullständig kontroll över indatabearbetning, inklusive bindning, återanrop och validering. Komponenten kan användas i eller utanför ett Blazor formulär (EditForm).
  • Tar booleska indata från en kryssruta.
  • Ändrar bakgrundsfärgen om kryssrutan är markerad.

Koden i komponenten innehåller:

  • Egenskapen Value används med tvåvägsbindning för att hämta eller ange värdet för indata. ValueChanged är återanropet som uppdaterar det bundna värdet.

  • När det används i ett Blazor-format:

    • EditContext är ett kaskaderande värde.
    • fieldCssClass formatmallar fältet baserat på resultatet av EditContext validering.
    • ValueExpression är ett uttryck (Expression<Func<T>>) som tilldelats av ramverket som identifierar det bundna värdet.
    • FieldIdentifier identifierar unikt ett enda fält som kan redigeras, vilket vanligtvis motsvarar en modellegenskap. Fältidentifieraren skapas med uttrycket som identifierar det bundna värdet (ValueExpression).
  • I händelsehanteraren för OnChange:

    • Värdet för kryssrutans indata hämtas från InputFileChangeEventArgs.
    • Bakgrundsfärgen och textfärgen för containern <div> element anges.
    • EventCallback.InvokeAsync anropar ombudet som är associerat med bindningen och skickar ett händelsemeddelande till konsumenter om att värdet har ändrats.
    • Om komponenten används i en EditForm (egenskapen EditContext inte är null) anropas EditContext.NotifyFieldChanged för att utlösa verifiering.

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

Om du vill använda föregående komponent i exempelformuläret rymdskepp (Starship3.razor/Starship.cs)ersätter du <div>-blocket för fältet för tekniskt godkännande med en EngineeringApprovalInputStandalone komponentinstans som är bunden till modellens IsValidatedDesign-egenskap:

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

Komponenten EngineeringApprovalInputStandalone fungerar också utanför en EditForm:

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

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

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

Alternativknappar

Exemplet i denna sektion baseras på -formuläret (-komponenten) i avsnittet av Exempelformulär i denna artikel.

Lägg till följande enum typer i appen. Skapa en ny fil för att lagra dem eller lägg till dem i Starship.cs-filen.

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

Gör klassen ComponentEnums tillgänglig för:

  • Starship-modellen i Starship.cs (till exempel using static ComponentEnums;).
  • Starfleet Starship Database-formulär (Starship3.razor) (till exempel @using static ComponentEnums).

Använd komponenterna InputRadio<TValue> tillsammans med komponenten InputRadioGroup<TValue> för att skapa en alternativknappsgrupp. I följande exempel läggs egenskaper till i Starship-modellen som beskrivs i avsnittet Exempelformulär i artikeln Indatakomponenter:

[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;

Uppdatera formuläret Starfleet Starship Database (Starship3 komponent) i avsnittet Exempelformulär i artikeln Indatakomponenter. Lägg till komponenterna för att producera:

  • En alternativknappsgrupp för fartygstillverkaren.
  • En kapslad alternativknappgrupp för motor- och skeppsfärg.

Note

Inbäddade radioknappsgrupper används inte ofta i formulär eftersom de kan leda till en oorganiserad formulärlayout som kan förvirra användarna. Det finns dock fall då de är meningsfulla i UI-design, till exempel i följande exempel som parar rekommendationer för två användarindata, fartygsmotor och fartygsfärg. En motor och en färg krävs av formulärets validering. Formulärets layout använder kapslade InputRadioGroup<TValue>för att parkoppla motor- och färgrekommendationer. Användaren kan dock kombinera valfri motor med valfri färg för att skicka formuläret.

Note

Se till att göra ComponentEnums-klassen tillgänglig för komponenten i följande exempel:

@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>

Obs

Om Name utelämnas grupperas InputRadio<TValue> komponenter efter deras senaste förfader.

Om du implementerade föregående Razor-markering i Starship3-komponenten i exempelformuläret avsnittet Indatakomponenter artikeln uppdaterar du loggningen för metoden Submit:

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);

När du arbetar med alternativknappar i ett formulär hanteras databindning på ett annat sätt än för andra element eftersom alternativknappar betraktas som en grupp. Värdet för varje alternativknapp är fast, men värdet för alternativknappsgruppen är värdet för den valda alternativknappen. I följande exempel visas hur du:

  • Hantera databindning för en grupp radioknappar.
  • Stöd för validering med hjälp av en anpassad InputRadio<TValue> komponent.

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

Mer information om generiska typparametrar (@typeparam) finns i följande artiklar:

Använd följande exempelmodell.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

Följande RadioButtonExample komponent använder den föregående InputRadio komponenten för att hämta och verifiera ett omdöme från användaren:

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");
    }
}