Bagikan melalui


pengikatan formulir inti Blazor ASP.NET

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.

Peringatan

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.

Artikel ini menjelaskan cara menggunakan pengikatan dalam Blazor formulir.

EditForm/EditContext pola

Membuat EditForm berdasarkan objek yang EditContext ditetapkan sebagai nilai berskala untuk komponen lain dalam formulir. Metadata EditContext trek tentang proses edit, termasuk bidang formulir mana yang telah dimodifikasi dan pesan validasi saat ini. Menetapkan ke EditForm.Model atau dapat EditForm.EditContext mengikat formulir ke data.

Pengikatan model

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

Catatan

Sebagian besar contoh model formulir artikel ini mengikat formulir ke properti C#, tetapi pengikatan bidang C# juga didukung.

Pengikatan konteks

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

Tetapkan atau EditContext Model ke .EditForm Jika keduanya ditetapkan, kesalahan runtime dilemparkan.

Jenis yang didukung

Pengikatan mendukung:

  • Jenis primitif
  • Koleksi
  • Jenis kompleks
  • Jenis rekursif
  • Jenis dengan konstruktor
  • Enums

Anda juga dapat menggunakan [DataMember] atribut dan [IgnoreDataMember] untuk menyesuaikan pengikatan model. Gunakan atribut ini untuk mengganti nama properti, mengabaikan properti, dan menandai properti sesuai kebutuhan.

Opsi pengikatan tambahan

Opsi pengikatan model tambahan tersedia saat RazorComponentsServiceOptions memanggil AddRazorComponents:

Berikut ini menunjukkan nilai default yang ditetapkan oleh kerangka kerja:

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

Nama formulir

FormName Gunakan parameter untuk menetapkan nama formulir. Nama formulir harus unik untuk mengikat data model. Formulir berikut diberi nama RomulanAle:

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

Menyediakan nama formulir:

  • Diperlukan untuk semua formulir yang dikirimkan oleh komponen sisi server yang dirender secara statis.
  • Tidak diperlukan untuk formulir yang dikirimkan oleh komponen yang dirender secara interaktif, yang mencakup formulir dalam Blazor WebAssembly aplikasi dan komponen dengan mode render interaktif. Namun, sebaiknya berikan nama formulir unik untuk setiap formulir untuk mencegah kesalahan posting formulir runtime jika interaktivitas pernah dihilangkan untuk formulir.

Nama formulir hanya diperiksa ketika formulir diposting ke titik akhir sebagai permintaan HTTP POST tradisional dari komponen sisi server yang dirender secara statis. Kerangka kerja tidak melemparkan pengecualian pada titik penyajian formulir, tetapi hanya pada saat HTTP POST tiba dan tidak menentukan nama formulir.

Ada cakupan formulir yang tidak disebutkan namanya (string kosong) di atas komponen akar aplikasi, yang cukup ketika tidak ada tabrakan nama formulir di aplikasi. Jika tabrakan nama formulir dimungkinkan, seperti saat menyertakan formulir dari pustaka dan Anda tidak memiliki kontrol atas nama formulir yang digunakan oleh pengembang pustaka, berikan cakupan nama formulir dengan FormMappingScope komponen dalam Blazor Web Appproyek utama.

Dalam contoh berikut, HelloFormFromLibrary komponen memiliki formulir bernama Hello dan berada di pustaka.

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

Komponen berikut NamedFormsWithScope menggunakan komponen pustaka HelloFormFromLibrary dan juga memiliki formulir bernama Hello. Nama FormMappingScope cakupan komponen adalah ParentContext untuk formulir apa pun yang disediakan oleh HelloFormFromLibrary komponen. Meskipun kedua formulir dalam contoh ini memiliki nama formulir (Hello), nama formulir tidak bertabrakan dan peristiwa dirutekan ke formulir yang benar untuk peristiwa POST formulir.

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

Menyediakan parameter dari formulir ([SupplyParameterFromForm])

Atribut [SupplyParameterFromForm] menunjukkan bahwa nilai properti terkait harus disediakan dari data formulir untuk formulir. Data dalam permintaan yang cocok dengan nama properti terikat ke properti . Input berdasarkan InputBase<TValue> hasilkan nama nilai formulir yang cocok dengan nama Blazor yang digunakan untuk pengikatan model. Tidak seperti properti parameter komponen ([Parameter]), properti yang dianotasi dengan [SupplyParameterFromForm] tidak perlu ditandai public.

Anda dapat menentukan parameter pengikatan formulir berikut ke [SupplyParameterFromForm] atribut :

  • Name: Mendapatkan atau mengatur nama untuk parameter . Nama ini digunakan untuk menentukan awalan yang akan digunakan untuk mencocokkan data formulir dan memutuskan apakah nilai perlu diikat atau tidak.
  • FormName: Mendapatkan atau mengatur nama untuk handler. Nama digunakan untuk mencocokkan parameter dengan formulir menurut nama formulir untuk memutuskan apakah nilai perlu diikat atau tidak.

Contoh berikut secara independen mengikat dua formulir ke modelnya berdasarkan nama formulir.

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

Formulir berlapis dan mengikat

Panduan berikut menunjukkan cara bersarang dan mengikat formulir anak.

Kelas detail pengiriman berikut (ShipDetails) menyimpan deskripsi dan panjang untuk subformulir.

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

Kelas berikut menamai Ship pengidentifikasi (Id) dan menyertakan detail pengiriman.

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

Subformulir berikut digunakan untuk mengedit nilai jenis ShipDetails . Ini diimplementasikan dengan mewarisi Editor<T> di bagian atas komponen. Editor<T> memastikan bahwa komponen anak menghasilkan nama bidang formulir yang benar berdasarkan model (T), di mana T dalam contoh berikut adalah 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>

Bentuk utama terikat ke Ship kelas . Komponen StarshipSubform ini digunakan untuk mengedit detail pengiriman, terikat sebagai 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);
}

Menginisialisasi data formulir dengan SSR statis

Ketika komponen mengadopsi SSR statis, OnInitialized{Async} metode siklus hidup dan OnParametersSet{Async} metode siklus hidup diaktifkan ketika komponen awalnya dirender dan pada setiap formulir POST ke server. Untuk menginisialisasi nilai model formulir, konfirmasikan apakah model sudah memiliki data sebelum menetapkan nilai model baru di , seperti yang ditunjukkan OnParametersSet{Async}contoh berikut.

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

Skenario kesalahan pemetaan formulir tingkat lanjut

Kerangka kerja membuat instans dan mengisi FormMappingContext formulir, yang merupakan konteks yang terkait dengan operasi pemetaan formulir tertentu. Setiap cakupan pemetaan (ditentukan oleh FormMappingScope komponen) membuat instans FormMappingContext. Setiap kali meminta konteks untuk nilai, kerangka kerja mengisi FormMappingContext dengan nilai yang [SupplyParameterFromForm] dicoba dan kesalahan pemetaan apa pun.

Pengembang tidak diharapkan untuk berinteraksi secara FormMappingContext langsung, karena ini terutama sumber data untuk InputBase<TValue>, EditContext, dan implementasi internal lainnya untuk menunjukkan kesalahan pemetaan sebagai kesalahan validasi. Dalam skenario kustom tingkat lanjut, pengembang dapat mengakses FormMappingContext langsung sebagai [CascadingParameter] untuk menulis kode kustom yang menggunakan nilai yang dicoba dan kesalahan pemetaan.

Komponen input kustom

Untuk skenario pemrosesan input kustom, sub bagian berikut menunjukkan komponen input kustom:

Kami menyarankan agar Anda memperoleh komponen InputBase<TValue> input kustom kecuali persyaratan tertentu mencegah Anda melakukannya. Kelas InputBase<TValue> ini secara aktif dikelola oleh tim ASP.NET Core, memastikannya tetap terbarui dengan fitur dan perubahan kerangka kerja terbaru Blazor .

Komponen input berdasarkan InputBase<T>

Contoh komponen berikut:

  • Mewarisi dari InputBase<TValue>. Komponen yang mewarisi harus InputBase<TValue> digunakan dalam Blazor bentuk (EditForm).
  • Mengambil input boolean dari kotak centang.
  • Mengatur warna latar belakang kontainernya <div> berdasarkan status kotak centang, yang terjadi ketika AfterChange metode dijalankan setelah pengikatan (@bind:after).
  • Diperlukan untuk mengambil alih metode kelas TryParseValueFromString dasar tetapi tidak memproses data input string karena kotak centang tidak menyediakan data string. Contoh implementasi TryParseValueFromString untuk jenis komponen input lain yang memproses input string tersedia di sumber referensi ASP.NET Core.

Catatan

Tautan dokumentasi ke sumber referensi .NET biasanya memuat cabang default repositori, yang mewakili pengembangan saat ini untuk rilis .NET berikutnya. Untuk memilih tag rilis tertentu, gunakan daftar dropdown Beralih cabang atau tag. Untuk informasi lebih lanjut, lihat Cara memilih tag versi kode sumber 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)}'.");
}

Untuk menggunakan komponen sebelumnya dalam formulir contoh starship (Starship.cs/Starship3.razor), ganti <div> blok untuk bidang persetujuan teknik dengan instans komponen yang EngineeringApprovalInputDerived terikat ke properti model:IsValidatedDesign

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

Komponen input dengan kontrol pengembang penuh

Contoh komponen berikut:

  • Tidak mewarisi dari InputBase<TValue>. Komponen mengambil kontrol penuh pemrosesan input, termasuk pengikatan, panggilan balik, dan validasi. Komponen dapat digunakan di dalam atau di luar Blazor formulir (EditForm).
  • Mengambil input boolean dari kotak centang.
  • Ubah warna latar belakang jika kotak centang dicentang.

Kode dalam komponen meliputi:

  • Properti Value digunakan dengan pengikatan dua arah untuk mendapatkan atau mengatur nilai input. ValueChanged adalah panggilan balik yang memperbarui nilai terikat.

  • Saat digunakan dalam Blazor formulir:

    • EditContext adalah nilai berskala.
    • fieldCssClass menata bidang berdasarkan hasil EditContext validasi.
    • ValueExpression adalah ekspresi (Expression<Func<T>>) yang ditetapkan oleh kerangka kerja yang mengidentifikasi nilai terikat.
    • FieldIdentifier secara unik mengidentifikasi satu bidang yang dapat diedit, biasanya sesuai dengan properti model. Pengidentifikasi bidang dibuat dengan ekspresi yang mengidentifikasi nilai terikat (ValueExpression).
  • Di penanganan OnChange aktivitas:

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

Untuk menggunakan komponen sebelumnya dalam formulir contoh starship (Starship.cs/Starship3.razor), ganti <div> blok untuk bidang persetujuan teknik dengan instans komponen yang EngineeringApprovalInputStandalone terikat ke properti model:IsValidatedDesign

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

Komponen EngineeringApprovalInputStandalone ini juga berfungsi di luar EditForm:

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

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

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

Tombol radio

Contoh di bagian ini didasarkan pada Starfleet Starship Database formulir (Starship3 komponen) dari bagian Formulir contoh dari artikel ini.

Tambahkan jenis berikut enum ke aplikasi. Buat file baru untuk menahannya atau menambahkannya ke Starship.cs file.

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 Buat kelas dapat diakses oleh:

  • Starship model di Starship.cs (misalnya, using static ComponentEnums;).
  • Starfleet Starship Database form (Starship3.razor) (misalnya, @using static ComponentEnums).

Gunakan InputRadio<TValue> komponen dengan InputRadioGroup<TValue> komponen untuk membuat grup tombol radio. Dalam contoh berikut, properti ditambahkan ke Starship model yang dijelaskan di bagian Formulir contoh dari artikel Komponen input:

[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 Perbarui formulir (Starship3 komponen) dari bagian Formulir contoh dari artikel Komponen input. Tambahkan komponen yang akan dihasilkan:

  • Grup tombol radio untuk produsen kapal.
  • Grup tombol radio berlapis untuk mesin dan warna pengiriman.

Catatan

Grup tombol radio berlapis tidak sering digunakan dalam formulir karena dapat mengakibatkan tata letak kontrol formulir yang tidak terorganisir yang dapat membingungkan pengguna. Namun, ada kasus ketika mereka masuk akal dalam desain UI, seperti dalam contoh berikut yang memasangkan rekomendasi untuk dua input pengguna, mesin pengiriman dan warna kapal. Satu mesin dan satu warna diperlukan oleh validasi formulir. Tata letak formulir menggunakan sarang berlapis untuk memasangkan InputRadioGroup<TValue>mesin dan rekomendasi warna. Namun, pengguna dapat menggabungkan mesin apa pun dengan warna apa pun untuk mengirimkan formulir.

Catatan

Pastikan untuk membuat ComponentEnums kelas tersedia untuk komponen untuk contoh berikut:

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

Catatan

Jika Name dihilangkan, InputRadio<TValue> komponen dikelompokkan oleh leluhur terbarunya.

Jika Anda menerapkan markup sebelumnya Razor di Starship3 komponen bagian Formulir contoh dari artikel Komponen input, perbarui pengelogan untuk Submit metode :

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

Saat bekerja dengan tombol radio dalam bentuk, pengikatan data ditangani secara berbeda dari elemen lain karena tombol radio dievaluasi sebagai grup. Nilai setiap tombol radio diperbaiki, tetapi nilai grup tombol radio adalah nilai tombol radio yang dipilih. Contoh berikut menunjukkan cara membatalkan pekerjaan.

  • Menangani pengikatan data untuk grup tombol radio.
  • Mendukung validasi menggunakan komponen kustom 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;
        }
    }
}

Untuk informasi selengkapnya tentang parameter jenis generik (@typeparam), lihat artikel berikut ini:

Gunakan contoh model berikut.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

Komponen berikut RadioButtonExample menggunakan komponen sebelumnya InputRadio untuk mendapatkan dan memvalidasi peringkat dari pengguna:

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