다음을 통해 공유


ASP.NET Core Blazor 양식 바인딩

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

이 문서에서는 양식에서 Blazor 바인딩을 사용하는 방법을 설명합니다.

EditForm / EditContext 모델

형식 EditFormEditContext 다른 구성 요소에 대한 연계 값으로 할당된 개체를 기반으로 합니다. 수정 EditContext 된 양식 필드와 현재 유효성 검사 메시지를 포함하여 편집 프로세스에 대한 메타데이터를 추적합니다. EditForm.Model 또는 EditForm.EditContext을 각각 할당하여 양식을 데이터에 바인딩할 수 있습니다.

모델 바인딩

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

참고 항목

이 문서의 양식 모델 예제 대부분은 C# 속성에 양식을 바인딩하지만 C# 필드 바인딩도 지원됩니다.

컨텍스트 바인딩

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

EditContext 중에 ModelEditForm에 할당합니다. 둘 다 할당되면 런타임 오류가 throw됩니다.

지원되는 유형

바인딩은 다음을 지원합니다.

  • 기본 형식
  • 컬렉션
  • 복합 형식
  • 재귀 형식
  • 생성자가 있는 형식
  • 열거형

[DataMember] 특성을 사용하여 [IgnoreDataMember] 모델 바인딩을 사용자 지정할 수도 있습니다. 이러한 특성을 사용하여 속성의 이름을 바꾸고, 속성을 무시하고, 필요에 따라 속성을 표시합니다.

추가 바인딩 옵션

다음을 호출RazorComponentsServiceOptions할 때 추가 모델 바인딩 옵션을 사용할 수 있습니다AddRazorComponents.

다음은 프레임워크에서 할당한 기본값을 보여 줍니다.

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

양식 이름

매개 변수를 FormName 사용하여 양식 이름을 할당합니다. 모델 데이터를 바인딩하려면 양식 이름이 고유해야 합니다. 다음 양식의 이름은 RomulanAle다음과 같습니다.

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

양식 이름 제공:

  • 정적으로 렌더링된 서버 쪽 구성 요소에 의해 제출되는 모든 양식에 필요합니다.
  • 대화형 렌더링 모드가 있는 앱 및 구성 요소의 양식을 포함하는 대화형으로 렌더링된 구성 요소에서 Blazor WebAssembly 제출하는 양식에는 필요하지 않습니다. 그러나 폼에 대해 대화형이 삭제된 경우 런타임 양식 게시 오류를 방지하기 위해 모든 양식에 고유한 양식 이름을 제공하는 것이 좋습니다.

양식 이름은 폼이 정적으로 렌더링된 서버 쪽 구성 요소의 기존 HTTP POST 요청으로 엔드포인트에 게시될 때만 확인됩니다. 프레임워크는 폼을 렌더링할 때 예외를 throw하지 않고 HTTP POST가 도착하고 양식 이름을 지정하지 않는 지점에서만 예외를 throw합니다.

앱의 루트 구성 요소 위에 명명되지 않은(빈 문자열) 양식 범위가 있으며, 앱에 양식 이름 충돌이 없으면 충분합니다. 라이브러리의 양식을 포함하고 라이브러리 개발자가 사용하는 양식 이름을 제어할 수 없는 경우와 같이 양식 이름 충돌이 발생할 수 있는 경우 '기본 프로젝트의 구성 요소FormMappingScope와 함께 Blazor Web App 양식 이름 범위를 제공합니다.

다음 예제에서 구성 요소에는 HelloFormFromLibrary 이름이 지정된 Hello 양식이 있으며 라이브러리에 있습니다.

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

다음 NamedFormsWithScope 구성 요소는 라이브러리의 HelloFormFromLibrary 구성 요소를 사용하며 이름이 같은 Hello폼도 있습니다. FormMappingScope 구성 요소의 범위 이름은 ParentContext 구성 요소에서 제공하는 모든 양식에 대한 HelloFormFromLibrary 것입니다. 이 예제의 두 폼에는 모두 양식 이름(Hello)이 있지만 양식 이름은 충돌하지 않으며 이벤트는 양식 POST 이벤트에 대해 올바른 양식으로 라우팅됩니다.

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

양식에서 매개 변수 제공([SupplyParameterFromForm])

이 특성은 [SupplyParameterFromForm] 양식의 양식 데이터에서 연결된 속성의 값을 제공해야 임을 나타냅니다. 속성 이름과 일치하는 요청의 데이터는 속성에 바인딩됩니다. 모델 바인딩에 InputBase<TValue> 사용되는 이름과 일치하는 양식 값 이름을 Blazor 기반으로 입력합니다. 구성 요소 매개 변수 속성()[Parameter]과 달리 주석이 [SupplyParameterFromForm] 추가된 속성은 표시 public할 필요가 없습니다.

특성[SupplyParameterFromForm] 지정할 수 있습니다.

  • Name: 매개 변수의 이름을 가져오거나 설정합니다. 이름은 양식 데이터를 일치시키고 값을 바인딩해야 하는지 여부를 결정하는 데 사용할 접두사를 결정하는 데 사용됩니다.
  • FormName: 처리기의 이름을 가져오거나 설정합니다. 이 이름은 매개 변수를 폼 이름으로 일치시켜 값을 바인딩해야 하는지 여부를 결정하는 데 사용됩니다.

다음 예제에서는 양식 이름으로 두 폼을 해당 모델에 독립적으로 바인딩합니다.

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

양식 중첩 및 바인딩

다음 지침에서는 자식 양식을 중첩하고 바인딩하는 방법을 보여 줍니다.

다음 선박 세부 정보 클래스(ShipDetails)는 하위 폼에 대한 설명과 길이를 포함합니다.

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

다음 Ship 클래스는 식별자(Id)의 이름을 지정하고 선박 세부 정보를 포함합니다.

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

다음 하위 폼은 형식의 값을 편집하는 ShipDetails 데 사용됩니다. 이는 구성 요소의 맨 위에 상속하여 Editor<T> 구현됩니다. Editor<T>는 다음 예제T에서 자식 구성 요소가 모델()TShipDetails을 기반으로 올바른 양식 필드 이름을 생성하도록 합니다.

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>

기본 폼은 클래스에 바인딩됩니다 Ship . 구성 StarshipSubform 요소는 배송 세부 정보를 편집하는 데 사용되며 다음과 같이 바인딩됩니다 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);
}

정적 SSR을 사용하여 양식 데이터 초기화

구성 요소가 정적 SSR OnInitialized{Async} 을 채택하면 구성 요소가 처음 렌더링되고 서버에 대한 모든 양식 POST에서 수명 주기 메서드OnParametersSet{Async} 와 수명 주기 메서드 가 발생합니다. 양식 모델 값을 초기화하려면 다음 예제와 같이 새 모델 값을 OnParametersSet{Async}할당하기 전에 모델에 이미 데이터가 있는지 확인합니다.

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

고급 양식 매핑 오류 시나리오

프레임워크는 지정된 양식의 매핑 작업과 연결된 컨텍스트인 폼에 대한 인스턴스화 및 채우기 FormMappingContext 를 수행합니다. 구성 요소에 의해 정의된 각 매핑 범위는 FormMappingScope 인스턴스화됩니다 FormMappingContext. 컨텍스트에 값을 요청할 때마다 [SupplyParameterFromForm] 프레임워크는 시도된 값과 매핑 오류로 채웁니다 FormMappingContext .

개발자는 매핑 오류를 유효성 검사 오류로 FormMappingContext 표시하기 위한 InputBase<TValue>EditContext데이터 원본 및 기타 내부 구현의 원본이기 때문에 직접 상호 작용할 필요가 없습니다. 고급 사용자 지정 시나리오에서 개발자는 시도된 값과 매핑 오류를 사용하는 사용자 지정 코드를 작성하기 위해 직접 FormMappingContext 액세스할 [CascadingParameter] 수 있습니다.

사용자 지정 입력 구성 요소

사용자 지정 입력 처리 시나리오의 경우 다음 하위 섹션에서는 사용자 지정 입력 구성 요소를 보여 줍니다.

  • 기반 InputBase<T>입력 구성 요소: 구성 요소는 바인딩, 콜백 및 유효성 검사에 대한 기본 구현을 제공하는 상속 InputBase<TValue>합니다. 상속 InputBase<TValue> 되는 구성 요소는 양식(Blazor)에서 EditForm 사용해야 합니다.

  • 전체 개발자 제어를 사용하는 입력 구성 요소: 구성 요소는 입력 처리를 완전히 제어합니다. 구성 요소의 코드는 바인딩, 콜백 및 유효성 검사를 관리해야 합니다. 구성 요소는 폼 내부 Blazor 또는 외부에서 사용할 수 있습니다.

특정 요구 사항으로 인해 사용자 지정 입력 구성 요소가 InputBase<TValue> 파생되지 않는 한 파생하는 것이 좋습니다. 이 InputBase<TValue> 클래스는 ASP.NET Core 팀에서 적극적으로 유지 관리하여 최신 Blazor 기능 및 프레임워크 변경 내용을 최신 상태로 유지합니다.

입력 구성 요소 기반 InputBase<T>

다음 예제 구성 요소는

  • InputBase<TValue>에서 상속됩니다. 상속 InputBase<TValue> 되는 구성 요소는 양식(Blazor)에서 EditForm 사용해야 합니다.
  • 확인란에서 부울 입력을 가져옵니다.
  • 바인딩 후<div> 메서드가 실행되면 발생하는 AfterChange 확인란의 상태에 따라 컨테이너 @bind:after 의 배경색을 설정합니다.
  • 기본 클래스의 메서드를 재정의 TryParseValueFromString 하는 데 필요하지만 확인란이 문자열 데이터를 제공하지 않으므로 문자열 입력 데이터를 처리하지 않습니다. 문자열 입력을 TryParseValueFromString 처리하는 다른 유형의 입력 구성 요소에 대한 구현 예제는 ASP.NET Core 참조 원본에서 사용할 수 있습니다.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 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)}'.");
}

선행 구성 요소를 우주선 예제 양식(Starship3.razor/Starship.cs)에서 사용하려면 엔지니어링 승인 필드의 블록을 모델의 <div> 속성에 바인딩된 구성 요소 인스턴스로 EngineeringApprovalInputDerived 바꿉 IsValidatedDesign 니다.

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

InputBase<TValue>를 상속하는 구성 요소가 언젠가 정적으로 렌더링될 때, InputBase<TValue>.NameAttributeValue 속성을 <input> 요소의 name 특성에 할당하십시오.

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

구성 요소가 항상 대화형으로 렌더링되도록 보장되는 경우에는 이전 할당이 필요하지 않습니다.

전체 개발자 제어가 있는 입력 구성 요소

다음 예제 구성 요소는

  • 에서 InputBase<TValue>상속되지 않습니다. 구성 요소는 바인딩, 콜백 및 유효성 검사를 포함하여 입력 처리를 완전히 제어합니다. 구성 요소는 폼(Blazor)의 EditForm 내부 또는 외부에서 사용할 수 있습니다.
  • 확인란에서 부울 입력을 가져옵니다.
  • 확인란이 선택되어 있으면 배경색을 변경합니다.

구성 요소의 코드에는 다음이 포함됩니다.

  • Value 속성은 양방향 바인딩과 함께 입력 값을 얻거나 설정하는 데 사용됩니다. ValueChanged 는 바인딩된 값을 업데이트하는 콜백입니다.

  • 양식에서 Blazor 사용하는 경우:

    • 계단 EditContext입니다.
    • fieldCssClass 는 유효성 검사 결과에 따라 필드의 EditContext 스타일을 지정합니다.
    • ValueExpression 는 바인딩된 값을 식별하는 프레임워크에서 할당한 식(Expression<Func<T>>)입니다.
    • FieldIdentifier 은 일반적으로 모델 속성에 해당하는 편집할 수 있는 단일 필드를 고유하게 식별합니다. 필드 식별자는 바인딩된 값(ValueExpression)을 식별하는 식을 사용하여 생성됩니다.
  • OnChange 이벤트 처리기에서:

    • 에서 확인란 입력 값을 가져옵니다 InputFileChangeEventArgs.
    • 컨테이너 <div> 요소의 배경색과 텍스트 색이 설정됩니다.
    • EventCallback.InvokeAsync 는 바인딩과 연결된 대리자를 호출하고 값이 변경되었다는 이벤트 알림을 소비자에게 디스패치합니다.
    • 구성 요소가 (속성이 EditForm 아닌 EditContext경우) null 에서 EditContext.NotifyFieldChanged 사용되는 경우 유효성 검사를 트리거하기 위해 호출됩니다.

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

선행 구성 요소를 starship 예제 양식(Starship3.razor/Starship.cs)에서 사용하려면 엔지니어링 승인 필드의 블록을 모델의 <div> 속성에 바인딩된 구성 요소 인스턴스로 EngineeringApprovalInputStandalone 바꿉 IsValidatedDesign 니다.

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

EngineeringApprovalInputStandalone 구성 요소는 다음 외부에서도 작동합니다.EditForm

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

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

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

라디오 단추

이 섹션의 예제는 이 문서의 예제 양식 섹션의 Starfleet Starship Database(Starship3구성 요소)을 기반으로 합니다.

앱에 다음 enum 유형을 추가합니다. 보관할 새 파일을 생성하거나 Starship.cs 파일에 추가합니다.

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 액세스할 수 있도록 합니다.

  • Starship 모델( Starship.cs 예: using static ComponentEnums;).
  • Starfleet Starship Database form(Starship3.razor)(예: @using static ComponentEnums)입니다.

InputRadio<TValue> 구성 요소와 함께 InputRadioGroup<TValue> 구성 요소를 사용하여 라디오 단추 그룹을 만듭니다. 다음 예제에서는 입력 구성 요소 문서의 예제 양식Starship설명된 모델에 속성이 추가 됩니다.

[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 입력 구성 요소 문서의 예제 양식 섹션에 있는 Starship3(구성 요소)을 업데이트합니다. 생성할 구성 요소를 추가합니다.

  • 선박 제조업체의 라디오 단추 그룹.
  • Ship 색상 및 엔진에 해당하는 중첩된 라디오 단추 그룹.

참고 항목

중첩된 라디오 단추 그룹은 사용자에게 혼란을 줄 수 있는 양식 컨트롤의 구성되지 않은 레이아웃을 만들 수 있기 때문에 양식에서 자주 사용되지 않습니다. 그러나 두 사용자의 입력과 Ship 엔진 및 Ship 색상에 대한 권장 사항을 결합하는 다음 예제와 같이 UI 디자인 측면에서 의미 있는 경우가 있습니다. 양식의 유효성 검사에는 하나의 엔진과 하나의 색상이 필요합니다. 양식의 레이아웃은 중첩된 InputRadioGroup<TValue>을 사용하여 엔진 및 색상 권장 사항을 쌍으로 만듭니다. 그러나 사용자는 모든 엔진과 모든 색을 결합하여 양식을 제출할 수 있습니다.

참고 항목

다음 예제에서는 구성 요소에서 ComponentEnums 클래스를 사용할 수 있도록 해야 합니다.

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

참고 항목

Name이 생략되면 InputRadio<TValue> 구성 요소가 가장 최근 상위 항목을 기준으로 그룹화됩니다.

입력 구성 요소 문서의 예제 양식Razor에서 Starship3 이전 태그를 구현한 경우 메서드에 대한 로깅을 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);

양식에서 라디오 단추를 사용하는 경우, 라디오 단추는 그룹으로 평가되기 때문에 데이터 바인딩이 다른 요소와 다르게 처리됩니다. 각 라디오 단추의 값은 고정되어 있지만 라디오 단추 그룹의 값은 선택한 라디오 단추의 값입니다. 아래 예제는 다음과 같은 작업의 방법을 보여 줍니다.

  • 라디오 단추 그룹의 데이터 바인딩을 처리합니다.
  • 사용자 지정 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;
        }
    }
}

제네릭 형식 매개 변수(@typeparam)에 대한 자세한 내용은 다음 문서를 참조하세요.

다음 예제 모델을 사용합니다.

StarshipModel.cs:

using System.ComponentModel.DataAnnotations;

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

다음 RadioButtonExample 구성 요소는 이전 InputRadio 구성 요소를 사용하여 사용자의 평가를 가져오고 유효성을 검사합니다.

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