Sdílet prostřednictvím


ASP.NET vazby základních Blazor formulářů

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete v tomto článku ve verzi .NET 9.

Tento článek vysvětluje, jak používat vazbu ve Blazor formulářích.

EditForm / EditContext model

EditForm Vytvoří EditContext na základě přiřazeného objektu kaskádovou hodnotu pro ostatní komponenty ve formuláři. Sleduje EditContext metadata procesu úprav, včetně toho, která pole formuláře byla změněna, a aktuální ověřovací zprávy. Přiřazení k formuláři EditForm.Model nebo k EditForm.EditContext datům může vytvořit vazbu.

Vazby modelu

Přiřazení: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();
}

Poznámka:

Většina příkladů modelu formulářů tohoto článku spojuje formuláře s vlastnostmi jazyka C#, ale vazba pole jazyka C# je podporována také.

Kontextová vazba

Přiřazení: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);
    }
}

Přiřaďte EditForm Pokud jsou oba přiřazené, vyvolá se chyba za běhu.

Podporované typy

Vazba podporuje:

  • Primitivní typy
  • Kolekce
  • Komplexní typy
  • Rekurzivní typy
  • Typy s konstruktory
  • Výčty

Vazby [DataMember][IgnoreDataMember] modelu můžete přizpůsobit také pomocí atributů. Pomocí těchto atributů můžete přejmenovat vlastnosti, ignorovat vlastnosti a označit vlastnosti jako povinné.

Další možnosti vazby

Při volání RazorComponentsServiceOptionsjsou k dispozici AddRazorComponents další možnosti vazby modelu:

Následující příklad ukazuje výchozí hodnoty přiřazené architekturou:

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

Názvy formulářů

Pomocí parametru FormName přiřaďte název formuláře. Názvy formulářů musí být jedinečné pro vytvoření vazby dat modelu. Následující formulář má název RomulanAle:

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

Zadání názvu formuláře:

  • Vyžaduje se pro všechny formuláře odeslané staticky vykreslenými komponentami na straně serveru.
  • Nevyžaduje se u formulářů odesílaných interaktivně vykreslenými komponentami, které zahrnují formuláře v Blazor WebAssembly aplikacích a komponentách s interaktivním režimem vykreslování. Doporučujeme však zadat jedinečný název formuláře pro každý formulář, aby se zabránilo chybám při publikování za běhu formuláře, pokud dojde k vyřazení interaktivity formuláře.

Název formuláře je kontrolován pouze v případech, kdy se formulář publikuje do koncového bodu jako tradiční požadavek HTTP POST ze staticky vykreslené součásti na straně serveru. Architektura nevyvolá výjimku v okamžiku vykreslení formuláře, ale pouze v okamžiku, kdy přijde http POST a nezadá název formuláře.

Nad kořenovou komponentou aplikace je obor formuláře bez názvu (prázdný řetězec), který stačí, když v aplikaci nedojde ke kolizi názvu formuláře. Pokud jsou možné kolize názvů formulářů, například při zahrnutí formuláře z knihovny a nemáte žádnou kontrolu nad názvem formuláře používaným vývojářem knihovny, zadejte obor názvu formuláře s FormMappingScope komponentou v Blazor Web Apphlavním projektu.

V následujícím příkladu HelloFormFromLibrary má komponenta název Hello formuláře a je v knihovně.

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

Následující NamedFormsWithScope komponenta používá komponentu knihovny HelloFormFromLibrary a má také formulář s názvem Hello. Název FormMappingScope oboru komponenty je ParentContext určen pro všechny formuláře zadané komponentou HelloFormFromLibrary . I když oba formuláře v tomto příkladu mají název formuláře (Hello), názvy formulářů nejsou kolidovány a události jsou směrovány do správného formuláře pro události POST formuláře.

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

Zadání parametru z formuláře ([SupplyParameterFromForm])

Atribut [SupplyParameterFromForm] označuje, že hodnota přidružené vlastnosti by měla být zadána z dat formuláře pro formulář. Data v požadavku, která odpovídají názvu vlastnosti, jsou svázaná s vlastností. Vstupy založené na InputBase<TValue> generování názvů hodnot formuláře, které odpovídají názvům Blazor , které se používají pro vazbu modelu. Na rozdíl od vlastností parametru komponenty ([Parameter]), vlastnosti anotované pomocí [SupplyParameterFromForm] nejsou nutné označit public.

Pro atribut[SupplyParameterFromForm] formuláře:

  • Name: Získá nebo nastaví název parametru. Název se používá k určení předpony, která se má použít ke shodě dat formuláře, a rozhodnutí, zda má být hodnota vázána nebo ne.
  • FormName: Získá nebo nastaví název obslužné rutiny. Název se používá ke shodě parametru s formulářem podle názvu formuláře, aby se rozhodl, zda je potřeba hodnotu vázat nebo ne.

Následující příklad nezávisle vytvoří vazbu dvou formulářů na jejich modely podle názvu formuláře.

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

Vnoření a vytvoření vazby formulářů

Následující doprovodné materiály ukazují, jak vnořit a svázat podřízené formuláře.

Následující třída podrobností o expediciShipDetails obsahuje popis a délku podformulář.

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

Následující Ship třída pojmenuje identifikátor (Id) a obsahuje podrobnosti o expedici.

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

Následující podformulář slouží k úpravě hodnot ShipDetails typu. To je implementováno děděním Editor<T> v horní části komponenty. Editor<T> zajišťuje, aby podřízená komponenta vygenerovala správné názvy polí formuláře na základě modelu (T), kde T v následujícím příkladu je 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>

Hlavní formulář je vázán na Ship třídu. Komponenta StarshipSubform slouží k úpravě podrobností o expedici svázané jako 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);
}

Inicializace dat formuláře pomocí statického SSR

Když komponenta přijme statickou službu SSR, spustí se metodaOnParametersSet{Async} počátečním vykreslení komponenty a na každém formuláři POST na server. Chcete-li inicializovat hodnoty modelu formuláře, ověřte, zda model již obsahuje data před přiřazením nových hodnot modelu v OnParametersSet{Async}, jak ukazuje následující příklad.

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

Pokročilé scénáře chyb mapování formulářů

Architektura vytvoří instanci formuláře a naplní FormMappingContext ho, což je kontext přidružený k operaci mapování daného formuláře. Vytvoří instanci každého oboru mapování (definovaného komponentouFormMappingScope).FormMappingContext Pokaždé, když se [SupplyParameterFromForm] zeptá kontextu na hodnotu, architektura naplní FormMappingContext pokusnou hodnotou a všechny chyby mapování.

Vývojáři se neočekává, že budou pracovat FormMappingContext přímo, protože se jedná hlavně o zdroj dat pro InputBase<TValue>, EditContexta další interní implementace, které ukazují chyby mapování jako chyby ověřování. V pokročilých vlastních scénářích můžou vývojáři přistupovat FormMappingContext přímo jako k zápisu vlastního [CascadingParameter] kódu, který využívá pokusy o hodnoty a chyby mapování.

Vlastní vstupní komponenty

V případě scénářů vlastního zpracování vstupu ukazují následující dílčí části vlastní vstupní komponenty:

Doporučujeme odvodit vlastní vstupní komponenty, pokud InputBase<TValue> vám to nezabrání konkrétní požadavky. Třída InputBase<TValue> je aktivně udržována týmem ASP.NET Core a zajišťuje, aby byla aktuální díky nejnovějším Blazor funkcím a změnám architektury.

Vstupní komponenta založená na InputBase<T>

Následující ukázková komponenta:

  • Dědí z InputBase<TValue>. Součásti, které dědí od InputBase<TValue> , musí být použity ve formuláři Blazor (EditForm).
  • Přebírá logický vstup ze zaškrtávacího políčka.
  • Nastaví barvu pozadí kontejneru <div> na základě stavu zaškrtávacího políčka, ke kterému dojde při AfterChange spuštění metody po vazbě (@bind:after).
  • Je nutné přepsat metodu TryParseValueFromString základní třídy, ale nezpracuje řetězcová vstupní data, protože zaškrtávací políčko neposkytuje řetězcová data. Ukázkové TryParseValueFromString implementace pro jiné typy vstupních komponent, které zpracovávají řetězcový vstup, jsou k dispozici v referenčním zdroji ASP.NET Core.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (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)}'.");
}

Pokud chcete použít předchozí komponentu ve formuláři příkladu hvězdicové lodi (Starship3.razor/Starship.cs), nahraďte <div> blok pro pole EngineeringApprovalInputDerived technického schválení instancí instancí komponenty vázanou na vlastnost modelu:IsValidatedDesign

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

Pokud se komponenta, která dědí z InputBase<TValue>, někdy staticky vykreslí, přiřaďte vlastnost InputBase<TValue>.NameAttributeValue atributu name u elementů <input>:

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

Předchozí přiřazení není nutné, pokud je zaručeno, že se komponenta bude vždy vykreslovat interaktivně.

Vstupní komponenta s úplným ovládáním pro vývojáře

Následující ukázková komponenta:

  • Nedědí z InputBase<TValue>. Komponenta přebírá úplnou kontrolu nad zpracováním vstupu, včetně vazby, zpětných volání a ověřování. Komponentu lze použít uvnitř formuláře nebo mimo ho Blazor (EditForm).
  • Přebírá logický vstup ze zaškrtávacího políčka.
  • Změní barvu pozadí, pokud je políčko zaškrtnuté.

Kód v komponentě zahrnuje:

  • Vlastnost Value se používá s obousměrnou vazbou k získání nebo nastavení hodnoty vstupu. ValueChanged je zpětné volání, které aktualizuje vázanou hodnotu.

  • Při použití ve formuláři Blazor :

    • Jedná se EditContext o kaskádovou hodnotu.
    • fieldCssClass v závislosti na výsledku EditContext ověření pole styluje.
    • ValueExpression je výraz (Expression<Func<T>>) přiřazený architekturou, která identifikuje vázanou hodnotu.
    • FieldIdentifier jedinečně identifikuje jedno pole, které lze upravit, obvykle odpovídající vlastnosti modelu. Identifikátor pole se vytvoří pomocí výrazu, který identifikuje vázanou hodnotu (ValueExpression).
  • V obslužné rutině OnChange události:

    • Hodnota vstupu zaškrtávacího políčka je získána z InputFileChangeEventArgs.
    • Nastaví se barva pozadí a barva textu prvku kontejneru <div> .
    • EventCallback.InvokeAsync vyvolá delegáta přidruženého k vazbě a odešle oznámení události příjemcům, že se hodnota změnila.
    • Pokud se komponenta používá v objektu EditForm ( EditContext vlastnost není null), EditContext.NotifyFieldChanged volá se k aktivaci ověření.

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

Pokud chcete použít předchozí komponentu ve formuláři příkladu hvězdicové lodi (Starship3.razor/Starship.cs), nahraďte <div> blok pro pole EngineeringApprovalInputStandalone technického schválení instancí instancí komponenty vázanou na vlastnost modelu:IsValidatedDesign

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

Komponenta EngineeringApprovalInputStandalone je také funkční mimo EditForm:

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

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

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

Přepínače

Příklad v této části je založen na Starfleet Starship Database formuláři (Starship3 komponentě) části Příklad formuláře tohoto článku.

Do aplikace přidejte následující enum typy . Vytvořte nový soubor pro jejich uložení nebo je přidejte do Starship.cs souboru.

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

ComponentEnums Zpřístupnění třídy pro:

  • Starship model in Starship.cs (například using static ComponentEnums;).
  • Starfleet Starship Database form () (Starship3.razornapříklad @using static ComponentEnums).

Pomocí InputRadio<TValue> komponent InputRadioGroup<TValue> vytvořte skupinu přepínačů. V následujícím příkladu Starship se vlastnosti přidají do modelu popsaného v části Příklad formuláře článku o vstupních komponentách :

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

Aktualizujte Starfleet Starship Database formulář (Starship3součást) části Příklad formuláře článku Vstupní komponenty. Přidejte komponenty, které se mají vytvořit:

  • Skupina přepínačů pro výrobce lodi.
  • Vnořená skupina přepínačů pro barvu motoru a lodi.

Poznámka:

Vnořené skupiny přepínačů se často nepoužívají ve formulářích, protože můžou vést k neuspořádanému rozložení ovládacích prvků formuláře, které můžou uživatele zmást. Existují však případy, kdy mají smysl v návrhu uživatelského rozhraní, například v následujícím příkladu, který spáruje doporučení pro dva vstupy uživatelů, modul lodí a barvu lodi. Ověření formuláře vyžaduje jeden modul a jednu barvu. Rozložení formuláře používá vnořené InputRadioGroup<TValue>čáry ke spárování motoru a doporučení barev. Uživatel ale může zkombinovat libovolný modul s libovolnou barvou a odeslat formulář.

Poznámka:

Ujistěte se, že ComponentEnums je třída dostupná pro komponentu v následujícím příkladu:

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

Poznámka:

Pokud Name je vynechán, InputRadio<TValue> komponenty jsou seskupené podle jejich nejnovějšího nadřazeného objektu.

Pokud jste implementovali předchozí kód v Razor komponentě Starship3 oddílu Vstupní komponenty článku, aktualizujte protokolování pro metodu: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);

Při práci s přepínači ve formuláři se datová vazba zpracovává jinak než jiné prvky, protože přepínače se vyhodnocují jako skupina. Hodnota každého přepínače je pevná, ale hodnota skupiny přepínačů je hodnota vybraného přepínače. Následující příklad ukazuje, jak:

  • Zpracování datové vazby pro skupinu přepínačů
  • Podpora ověřování pomocí vlastní InputRadio<TValue> komponenty

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

Další informace o parametrech obecného typu (@typeparam) najdete v následujících článcích:

Použijte následující ukázkový model.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

Následující RadioButtonExample komponenta používá předchozí InputRadio komponentu k získání a ověření hodnocení od uživatele:

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