ASP.NET Core Blazor formları bağlama

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Bu makalede, bağlamanın formlarda Blazor nasıl kullanılacağı açıklanmaktadır.

EditForm/EditContext model

, EditForm formdaki diğer bileşenler için basamaklı değer olarak atanan nesneyi temel alan bir EditContextoluşturur. Hangi EditContext form alanlarının değiştirildiği ve geçerli doğrulama iletileri de dahil olmak üzere düzenleme işlemiyle ilgili meta verileri izler. veya EditForm.EditContext öğesine EditForm.Model atamak, formu verilere bağlayabilir.

Model bağlama

Atama:EditForm.Model

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

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

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

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

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

Not

Bu makalenin form modeli örneklerinin çoğu formları C# özelliklerine bağlar, ancak C# alan bağlaması da desteklenir.

Bağlam bağlama

Atama:EditForm.EditContext

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

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    public 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);
    }
}

öğesine birEditContext veya a Model atayınEditForm. Her ikisi de atanmışsa bir çalışma zamanı hatası oluşur.

Desteklenen türler

Bağlama şu desteği destekler:

  • İlkel türler
  • Koleksiyonlar
  • Karmaşık türler
  • Özyinelemeli türler
  • Oluşturucuları olan türler
  • Numaralandırmalar

Model bağlamasını [DataMember] özelleştirmek için ve [IgnoreDataMember] özniteliklerini de kullanabilirsiniz. Özellikleri yeniden adlandırmak, özellikleri yoksaymak ve özellikleri gerektiği gibi işaretlemek için bu öznitelikleri kullanın.

Ek bağlama seçenekleri

çağrılırken AddRazorComponentsek RazorComponentsServiceOptions model bağlama seçenekleri sağlanır:

Aşağıda, çerçeve tarafından atanan varsayılan değerler gösterilmektedir:

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

Form adları

Form adı atamak için parametresini FormName kullanın. Form adlarının model verilerini bağlamak için benzersiz olması gerekir. Aşağıdaki formun adı RomulanAle:

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

Form adı sağlama:

  • Statik olarak işlenmiş sunucu tarafı bileşenleri tarafından gönderilen tüm formlar için gereklidir.
  • Etkileşimli işleme moduna sahip uygulamalardaki ve bileşenlerdeki Blazor WebAssembly formları içeren etkileşimli olarak işlenmiş bileşenler tarafından gönderilen formlar için gerekli değildir. Ancak, bir form için etkileşim bırakılırsa çalışma zamanı formu gönderme hatalarını önlemek için her form için benzersiz bir form adı sağlamanızı öneririz.

Form adı yalnızca form statik olarak işlenmiş bir sunucu tarafı bileşeninden geleneksel bir HTTP POST isteği olarak bir uç noktaya gönderildiğinde denetlenebilir. Çerçeve, formu işleme noktasında bir özel durum oluşturmaz, ancak yalnızca HTTP POST'un geldiği ve form adı belirtmediği noktada özel durum oluşturur.

Varsayılan olarak, uygulamanın kök bileşeninin üzerinde adsız (boş dize) form kapsamı vardır ve bu kapsam uygulamada form adı çakışmaları olmadığında yeterlidir. Form adı çakışmaları mümkünse (örneğin, bir kitaplıktan form eklerken ve kitaplığın geliştiricisi tarafından kullanılan form adı denetimine sahip değilseniz, Web Uygulamasının FormMappingScope ana projesindeki Blazor bileşenle bir form adı kapsamı sağlayın.

Aşağıdaki örnekte, bileşenin HelloFormFromLibrary adlı Hello bir formu vardır ve bir kitaplıktadır.

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]
    public string? Name { get; set; }

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

Aşağıdaki NamedFormsWithScope bileşen kitaplığın HelloFormFromLibrary bileşenini kullanır ve adlı Hellobir forma sahiptir. Bileşenin FormMappingScope kapsam adı, ParentContext bileşen tarafından sağlanan tüm formlara yöneliktir HelloFormFromLibrary . Bu örnekteki her iki form da form adına ()Hello sahip olsa da, form adları harmanlamaz ve olaylar form POST olayları için doğru forma yönlendirilir.

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]
    public string? Name { get; set; }

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

Formdan bir parametre sağlayın ([SupplyParameterFromForm])

özniteliği, [SupplyParameterFromForm] ilişkili özelliğin değerinin formun form verilerinden sağlanması gerektiğini gösterir. İstekteki, özelliğin adıyla eşleşen veriler özelliğine bağlıdır. Model bağlama için kullanılan adlarla eşleşen form değeri adları Blazor oluşturmaya dayalı InputBase<TValue> girişler.

Özniteliğine aşağıdaki form bağlama parametrelerini [SupplyParameterFromForm] belirtebilirsiniz:

  • Name: Parametresinin adını alır veya ayarlar. Ad, form verileriyle eşleştirmek için kullanılacak ön eki belirlemek ve değerin bağlanması gerekip gerekmediğine karar vermek için kullanılır.
  • FormName: İşleyicinin adını alır veya ayarlar. Ad, değerin bağlanması gerekip gerekmediğine karar vermek için parametreyi form adına göre formla eşleştirmek için kullanılır.

Aşağıdaki örnek, modellerine form adına göre iki formu bağımsız olarak bağlar.

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")]
    public Holodeck? Model1 { get; set; }

    [SupplyParameterFromForm(FormName = "Holodeck2")]
    public 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; }
    }
}

Formları iç içe yerleştirme ve bağlama

Aşağıdaki kılavuzda alt formları iç içe yerleştirme ve bağlama işlemleri gösterilmektedir.

Aşağıdaki ship details sınıfı (ShipDetails), bir alt form için bir açıklama ve uzunluk içerir.

ShipDetails.cs:

namespace BlazorSample;

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

Aşağıdaki Ship sınıf bir tanımlayıcıyı (Id) adlandırıp gönderim ayrıntılarını içerir.

Ship.cs:

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

Aşağıdaki alt form türün ShipDetails değerlerini düzenlemek için kullanılır. Bu, bileşenin en üstünde devralınarak Editor<T> uygulanır. Editor<T> alt bileşenin modeleT ( ) göre doğru form alanı adlarını oluşturmasını sağlar; burada T aşağıdaki örnekte yer alır ShipDetails.

StarshipSubform.razor:

@inherits Editor<ShipDetails>

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

Ana form sınıfa Ship bağlıdır. Bileşen StarshipSubform , olarak Model!.Detailsbağlı olan gemi ayrıntılarını düzenlemek için kullanılır.

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

Gelişmiş form eşleme hata senaryoları

Çerçeve, belirli bir formun FormMappingContext eşleme işlemiyle ilişkili bağlam olan formun örneğini oluşturur ve doldurur. Her eşleme kapsamı (bir FormMappingScope bileşen tarafından tanımlanır) örneği oluşturur FormMappingContext. Bir [SupplyParameterFromForm] değerin bağlamını her istediğinde, çerçeve denenen değerle ve eşleme hatalarıyla doldurur FormMappingContext .

Genellikle eşleme hatalarını doğrulama hataları olarak göstermek için , EditContextve diğer iç uygulamalar için InputBase<TValue>bir veri kaynağı olduğundan geliştiricilerin doğrudan etkileşim FormMappingContext kurması beklenemez. Gelişmiş özel senaryolarda geliştiriciler, denenen değerleri ve eşleme hatalarını kullanan özel kod yazmak için doğrudan olarak [CascadingParameter] erişebilirFormMappingContext.

Radyo düğmeleri

Bu bölümdeki örnek, bu makalenin Starfleet Starship Database Örnek form bölümünün formuna (Starship3 bileşenine) dayanır.

Aşağıdaki enum türleri uygulamaya ekleyin. Bunları tutmak veya dosyaya eklemek için Starship.cs yeni bir dosya oluşturun.

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

sınıfını aşağıdakiler enums için erişilebilir hale getirin:

  • Starship modelinde Starship.cs (örneğin, using static ComponentEnums;).
  • Starfleet Starship Database form (Starship3.razor) (örneğin, @using static ComponentEnums).

Bir radyo düğmesi grubu oluşturmak için bileşenleri bileşenle birlikte InputRadioGroup<TValue> kullanınInputRadio<TValue>. Aşağıdaki örnekte özellikler, Giriş bileşenleri makalesinin StarshipÖrnek form bölümünde açıklanan modele eklenir:

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

Giriş bileşenleri makalesinin Örnek form bölümünün formunu (Starship3bileşeni) güncelleştirin.Starfleet Starship Database Üretecek bileşenleri ekleyin:

  • Gemi üreticisi için bir radyo düğmesi grubu.
  • Altyapı ve gemi rengi için iç içe radyo düğmesi grubu.

Not

İç içe radyo düğmesi grupları genellikle formlarda kullanılmaz çünkü kullanıcıların kafasını karıştırabilecek biçim denetimlerinin düzensiz düzenine neden olabilir. Ancak, kullanıcı arabirimi tasarımında anlamlı oldukları durumlar vardır; örneğin, aşağıdaki örnekte iki kullanıcı girişi için önerileri eşleştiren durumlar vardır: ship engine ve ship color. Formun doğrulaması için bir altyapı ve bir renk gereklidir. Formun düzeni, altyapı ve renk önerilerini eşleştirmek için iç içe InputRadioGroup<TValue>yerleştirilmiş'leri kullanır. Ancak, kullanıcı formu göndermek için herhangi bir altyapıyı herhangi bir renkle birleştirebilir.

Not

Aşağıdaki örnekte sınıfın ComponentEnums bileşen tarafından kullanılabilir olduğundan emin olun:

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

Not

Atlanırsa Name , InputRadio<TValue> bileşenler en son atalarına göre gruplandırılır.

Giriş bileşenleri makalesinin Örnek form bölümünün bileşeninde Starship3 önceki Razor işaretlemeyi uyguladıysanız, yönteminin günlüğünü güncelleştirinSubmit:

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

Bir formda radyo düğmeleriyle çalışırken, radyo düğmeleri grup olarak değerlendirildiğinden veri bağlama diğer öğelerden farklı işlenir. Her radyo düğmesinin değeri sabittir, ancak radyo düğmesi grubunun değeri seçili radyo düğmesinin değeridir. Aşağıdaki örnekte şunların nasıl yapılacağını gösterilmektedir:

  • Radyo düğmesi grubu için veri bağlamayı işleme.
  • Özel InputRadio<TValue> bir bileşen kullanarak doğrulamayı destekler.

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

Genel tür parametreleri (@typeparam ) hakkında daha fazla bilgi için aşağıdaki makalelere bakın:

Aşağıdaki örnek modeli kullanın.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

Aşağıdaki RadioButtonExample bileşen, kullanıcıdan derecelendirme almak ve doğrulamak için önceki InputRadio bileşeni kullanır:

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