Udostępnij za pośrednictwem


powiązanie formularzy ASP.NET Core Blazor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak używać powiązania w Blazor formularzach.

EditForm/EditContext model

Obiekt EditForm tworzy EditContext obiekt oparty na przypisanym obiekcie jako wartość kaskadową dla innych składników w formularzu. Śledzi EditContext metadane dotyczące procesu edycji, w tym pola formularza, które zostały zmodyfikowane, oraz bieżące komunikaty sprawdzania poprawności. Przypisanie do obiektu EditForm.Model lub EditForm.EditContext może powiązać formularz z danymi.

Powiązanie modelu

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

Uwaga

Większość przykładów modelu formularzy tego artykułu wiąże formularze z właściwościami języka C#, ale obsługiwane jest również powiązanie pól języka C#.

Powiązanie kontekstu

Przypisanie do :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);
    }
}

Przypisz element EditContext lub do Model elementu EditForm. Jeśli oba te elementy zostaną przypisane, zostanie zgłoszony błąd środowiska uruchomieniowego.

Obsługiwane typy

Powiązanie obsługuje:

  • Typy pierwotne
  • Kolekcje
  • Typy złożone
  • Typy rekursywne
  • Typy z konstruktorami
  • Wyliczenia

Można również użyć [DataMember] atrybutów i [IgnoreDataMember] , aby dostosować powiązanie modelu. Użyj tych atrybutów, aby zmienić nazwy właściwości, zignorować właściwości i oznaczyć właściwości zgodnie z potrzebami.

Dodatkowe opcje powiązania

Dodatkowe opcje powiązania modelu są dostępne podczas RazorComponentsServiceOptions wywoływania elementu AddRazorComponents:

Poniżej przedstawiono wartości domyślne przypisane przez strukturę:

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

Nazwy formularzy

Użyj parametru , FormName aby przypisać nazwę formularza. Nazwy formularzy muszą być unikatowe w celu powiązania danych modelu. Następujący formularz nosi nazwę RomulanAle:

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

Podawanie nazwy formularza:

  • Jest wymagany dla wszystkich formularzy przesyłanych przez statycznie renderowane składniki po stronie serwera.
  • Nie jest wymagane w przypadku formularzy przesyłanych przez składniki renderowane interaktywnie, w tym formularze w Blazor WebAssembly aplikacjach i składnikach z trybem renderowania interakcyjnego. Zalecamy jednak podanie unikatowej nazwy formularza dla każdego formularza, aby zapobiec wysyłaniu błędów formularza w czasie wykonywania, jeśli kiedykolwiek przerywana jest interakcyjność dla formularza.

Nazwa formularza jest sprawdzana tylko wtedy, gdy formularz jest publikowany w punkcie końcowym jako tradycyjne żądanie HTTP POST ze statycznie renderowanego składnika po stronie serwera. Struktura nie zgłasza wyjątku w momencie renderowania formularza, ale tylko w momencie nadejścia żądania HTTP POST i nie określa nazwy formularza.

Istnieje zakres formularza bez nazwy (pusty ciąg) powyżej składnika głównego aplikacji, który wystarczy, gdy w aplikacji nie ma kolizji nazw formularzy. Jeśli możliwe są kolizje nazw formularzy, na przykład w przypadku dołączania formularza z biblioteki i nie masz kontroli nad nazwą formularza używaną przez dewelopera biblioteki, podaj zakres nazw formularzy ze FormMappingScope składnikiem w Blazor Web Appgłównym projekcie biblioteki.

W poniższym przykładzie HelloFormFromLibrary składnik ma postać o nazwie Hello i znajduje się w bibliotece.

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

Poniższy NamedFormsWithScope składnik używa składnika biblioteki HelloFormFromLibrary , a także ma formularz o nazwie Hello. FormMappingScope Nazwa zakresu składnika dotyczy ParentContext dowolnych formularzy dostarczonych przez HelloFormFromLibrary składnik. Mimo że obie formularze w tym przykładzie mają nazwę formularza (Hello), nazwy formularzy nie zderzają się, a zdarzenia są kierowane do poprawnego formularza dla zdarzeń POST formularza.

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

Podaj parametr z formularza ([SupplyParameterFromForm])

Atrybut [SupplyParameterFromForm] wskazuje, że wartość skojarzonej właściwości powinna być dostarczana z danych formularza dla formularza. Dane w żądaniu, które pasują do nazwy właściwości, są powiązane z właściwością. Dane wejściowe oparte na InputBase<TValue> generowaniu nazw wartości formularza, które są zgodne z nazwami Blazor używanymi do powiązania modelu. W przeciwieństwie do właściwości parametru składnika ([Parameter]), właściwości z adnotacjami [SupplyParameterFromForm] nie są wymagane do oznaczenia public.

Do atrybutu [SupplyParameterFromForm]można określić następujące parametry powiązania formularza:

  • Name: Pobiera lub ustawia nazwę parametru. Nazwa służy do określania prefiksu używanego do dopasowania danych formularza i decydowania, czy wartość musi być powiązana.
  • FormName: Pobiera lub ustawia nazwę programu obsługi. Nazwa jest używana do dopasowania parametru do formularza według nazwy formularza, aby zdecydować, czy wartość musi być powiązana.

Poniższy przykład niezależnie wiąże dwa formularze z modelami według nazwy formularza.

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

Zagnieżdżanie i wiązanie formularzy

Poniższe wskazówki pokazują, jak zagnieżdżać i wiązać formularze podrzędne.

Następująca klasa szczegółów wysyłki (ShipDetails) zawiera opis i długość podformularza.

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

Poniższa Ship klasa nazywa identyfikator (Id) i zawiera szczegóły wysyłki.

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

Poniższy podformularz jest używany do edytowania ShipDetails wartości typu. Jest to implementowane przez dziedziczenie Editor<T> w górnej części składnika. Editor<T>gwarantuje, że składnik podrzędny generuje poprawne nazwy pól formularza na podstawie modelu (T), gdzie T w poniższym przykładzie jest .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>

Formularz główny jest powiązany z klasą Ship . Składnik służy do edytowania StarshipSubform szczegółów wysyłki powiązanej 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);
}

Inicjowanie danych formularza za pomocą statycznego przewodnika SSR

Gdy składnik przyjmuje statyczny SSR, metoda cyklu życia i OnParametersSet{Async} metoda cyklu życia są uruchamiane, OnInitialized{Async} gdy składnik jest początkowo renderowany i na każdym formularzu POST na serwerze. Aby zainicjować wartości modelu formularza, upewnij się, że model ma już dane przed przypisanie nowych wartości modelu w programie OnParametersSet{Async}, jak pokazano w poniższym przykładzie.

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

Zaawansowane scenariusze błędów mapowania formularzy

Struktura tworzy wystąpienie i wypełnia FormMappingContext formularz, który jest kontekstem skojarzonym z operacją mapowania danego formularza. Każdy zakres mapowania (zdefiniowany przez FormMappingScope składnik) tworzy wystąpienie FormMappingContext. Za każdym razem, gdy [SupplyParameterFromForm] element kontekst o wartość, struktura wypełnia FormMappingContext element wartością próbną i wszelkimi błędami mapowania.

Deweloperzy nie powinni korzystać bezpośrednio, FormMappingContext ponieważ jest to głównie źródło danych dla InputBase<TValue>programu , EditContexti innych wewnętrznych implementacji w celu wyświetlania błędów mapowania jako błędów walidacji. W zaawansowanych scenariuszach niestandardowych deweloperzy mogą uzyskiwać dostęp FormMappingContext bezpośrednio jako element [CascadingParameter] do pisania kodu niestandardowego, który korzysta z próbowanych wartości i błędów mapowania.

Niestandardowe składniki wejściowe

W przypadku niestandardowych scenariuszy przetwarzania danych wejściowych w poniższych podsekcjach przedstawiono niestandardowe składniki wejściowe:

Zalecamy tworzenie niestandardowych składników wejściowych, InputBase<TValue> chyba że określone wymagania uniemożliwiają wykonanie tych czynności. Klasa InputBase<TValue> jest aktywnie utrzymywana przez zespół ASP.NET Core, zapewniając, że jest aktualna dzięki najnowszym Blazor funkcjom i zmianom struktury.

Składnik wejściowy na podstawie InputBase<T>

Poniższy przykładowy składnik:

  • Dziedziczy z obiektu InputBase<TValue>. Składniki dziedziczone z InputBase<TValue> programu muszą być używane w formularzu Blazor (EditForm).
  • Pobiera dane wejściowe logiczne z pola wyboru.
  • Ustawia kolor tła kontenera <div> na podstawie stanu pola wyboru, który występuje, gdy AfterChange metoda jest wykonywana po powiązaniu (@bind:after).
  • Wymagane jest zastąpienie metody klasy TryParseValueFromString bazowej, ale nie przetwarza danych wejściowych ciągu, ponieważ pole wyboru nie dostarcza danych ciągów. Przykładowe implementacje TryParseValueFromString dla innych typów składników wejściowych, które przetwarzają dane wejściowe ciągu, są dostępne w źródle referencyjnym ASP.NET Core.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy 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)}'.");
}

Aby użyć poprzedniego składnika w przykładowym formularzu starship (Starship3.razor/Starship.cs), zastąp <div> blok pola zatwierdzenia inżynieryjnego wystąpieniem składnika powiązanym EngineeringApprovalInputDerived z właściwością modelu IsValidatedDesign :

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

Składnik wejściowy z pełną kontrolą dewelopera

Poniższy przykładowy składnik:

  • Nie dziedziczy z elementu InputBase<TValue>. Składnik przejmuje pełną kontrolę nad przetwarzaniem wejściowym, w tym powiązaniem, wywołaniami zwrotnymi i walidacją. Składnik może być używany wewnątrz lub na zewnątrz Blazor formularza (EditForm).
  • Pobiera dane wejściowe logiczne z pola wyboru.
  • Zmienia kolor tła, jeśli pole wyboru jest zaznaczone.

Kod w składniku obejmuje:

  • Właściwość Value jest używana z powiązaniem dwukierunkowym, aby uzyskać lub ustawić wartość danych wejściowych. ValueChanged to wywołanie zwrotne, które aktualizuje powiązaną wartość.

  • W przypadku użycia w formularzu Blazor :

    • Jest EditContext to wartość kaskadowa.
    • fieldCssClass style pola na podstawie wyniku weryfikacji EditContext .
    • ValueExpression jest wyrażeniem (Expression<Func<T>>) przypisanym przez strukturę identyfikującą powiązaną wartość.
    • FieldIdentifier unikatowo identyfikuje jedno pole, które można edytować, zwykle odpowiadające właściwości modelu. Identyfikator pola jest tworzony za pomocą wyrażenia identyfikującego powiązaną wartość (ValueExpression).
  • W programie obsługi zdarzeń OnChange :

    • Wartość danych wejściowych pola wyboru jest uzyskiwana z InputFileChangeEventArgselementu .
    • Ustawiono kolor tła i kolor tekstu elementu kontenera <div> .
    • EventCallback.InvokeAsync wywołuje delegata skojarzonego z powiązaniem i wysyła powiadomienie o zdarzeniu do odbiorców, że wartość została zmieniona.
    • Jeśli składnik jest używany w elemencie EditForm (właściwość nie nulljest ), EditContext.NotifyFieldChanged jest wywoływany w celu wyzwolenia EditContext walidacji.

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

Aby użyć poprzedniego składnika w przykładowym formularzu starship (Starship3.razor/Starship.cs), zastąp <div> blok pola zatwierdzenia inżynieryjnego wystąpieniem składnika powiązanym EngineeringApprovalInputStandalone z właściwością modelu IsValidatedDesign :

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

Składnik EngineeringApprovalInputStandalone działa również poza elementem EditForm:

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

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

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

Przycisków

Przykład w tej sekcji jest oparty na formularzu Starfleet Starship Database (Starship3 składnik) sekcji Przykładowy formularz tego artykułu.

Dodaj następujące enum typy do aplikacji. Utwórz nowy plik do przechowywania lub dodaj go do Starship.cs pliku.

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

Udostępnij klasę ComponentEnums :

  • Starship model in Starship.cs (na przykład using static ComponentEnums;).
  • Starfleet Starship Database form () (Starship3.razorna przykład @using static ComponentEnums).

Użyj InputRadio<TValue> składników ze składnikiem InputRadioGroup<TValue> , aby utworzyć grupę przycisków radiowych. W poniższym przykładzie właściwości są dodawane do Starship modelu opisanego w sekcji Przykładowy formularz artykułu Składniki wejściowe:

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

Starfleet Starship Database Zaktualizuj formularz (Starship3składnik) sekcji Przykładowy formularz artykułu Składniki wejściowe. Dodaj składniki do utworzenia:

  • Grupa przycisków radiowych dla producenta statku.
  • Zagnieżdżona grupa przycisków radiowych dla silnika i koloru wysyłki.

Uwaga

Zagnieżdżone grupy przycisków radiowych nie są często używane w formularzach, ponieważ mogą one spowodować dezorganizowany układ kontrolek formularzy, które mogą mylić użytkowników. Istnieją jednak przypadki, gdy mają sens w projekcie interfejsu użytkownika, na przykład w poniższym przykładzie, które łączą zalecenia dotyczące dwóch danych wejściowych użytkownika, silnika wysyłkowego i koloru wysyłki. Jeden aparat i jeden kolor są wymagane przez walidację formularza. Układ formularza używa zagnieżdżonych InputRadioGroup<TValue>elementów do parowania aparatu i zaleceń dotyczących kolorów. Jednak użytkownik może połączyć dowolny aparat z dowolnym kolorem, aby przesłać formularz.

Uwaga

Upewnij się, że ComponentEnums klasa jest dostępna dla składnika w następującym przykładzie:

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

Uwaga

Jeśli Name pominięto, InputRadio<TValue> składniki są pogrupowane według ich najnowszego modułu ancestor.

Jeśli zaimplementowano powyższy Razor znacznik w Starship3 składniku sekcji Przykładowy formularz artykułu Składniki wejściowe, zaktualizuj rejestrowanie dla Submit metody :

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

Podczas pracy z przyciskami radiowymi w formularzu powiązanie danych jest obsługiwane inaczej niż inne elementy, ponieważ przyciski radiowe są oceniane jako grupa. Wartość każdego przycisku radiowego jest stała, ale wartość grupy przycisków radiowych jest wartością wybranego przycisku radiowego. W poniższym przykładzie pokazano, jak:

  • Obsługa powiązania danych dla grupy przycisków radiowych.
  • Obsługa walidacji przy użyciu składnika niestandardowego InputRadio<TValue> .

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

Aby uzyskać więcej informacji na temat ogólnych parametrów typu (@typeparam), zobacz następujące artykuły:

Użyj następującego przykładowego modelu.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

RadioButtonExample Poniższy składnik używa poprzedniego InputRadio składnika do uzyskania i zweryfikowania oceny od użytkownika:

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