簡體   English   中英

如何在 Blazor 組件上進行雙向綁定

[英]How to make two-way binding on Blazor component

我想創建自定義輸入,所以我創建了這個組件:

MyInputComponent.razor

<div>
  <input type="text" @bind="BindingValue" />
</div>

@code {
    [Parameter]
    public string BindingValue { get; set; }
}

然后是用法:

<EditForm Model="model" OnValidSubmit="Submit">
    <MyInputComponent BindingValue="model.Name" />
</EditForm>

@code {
    User model = new User() { Name = "My Name" };

    private void Submit()
    {
       // here I found model.Name = null;
   }
}

當我調試MyInputComponent時,我發現了我輸入的值。 但是當我提交表單時,該值為空。

什么東西少了?

快速回答

引用Blazor 文檔

組件參數

綁定識別組件參數,其中@bind-{property} 可以跨組件綁定屬性值。

對於您的頁面:

<EditForm Model="model" OnValidSubmit="Submit">
    <MyInputComponent @bind-BindingValue="model.Name" />
</EditForm>

子組件MyInputComponent

<div>
  <InputText type="text" @bind-Value="@BindingValue" />
</div>

@code {

    private string _value;

    [Parameter]
    public string BindingValue
    {
        get => _value;
        set
        {
            if (_value == value ) return;
            _value = value;
            BindingValueChanged.InvokeAsync(value);
        }
    }

    [Parameter]
    public EventCallback<string> BindingValueChanged { get; set; }   

}

注意

  • 您應該通過EventCallback<string> BindingValueChanged從子組件引發綁定更改。
  • 我選擇了BindingValueBindingValueChanged作為標識符,但是,您可以只使用ValueValueChanged 然后將是: <MyInputComponent @bind-Value="model.Name" />

在 BlazorFiddle 嘗試一下

已編輯:有關干凈的解決方案,請參閱下面的選項 2:


您在 EditForm 中的控件

如果您想將您的組件放在 EditForm 中並處理驗證,或使用 onchange 事件采取其他操作,您應該引發EditContext.NotifyFieldChanged 您有 2 個選項可以執行此操作。

選項 1:從 EditContext 提升

您可以從CascadeParameter獲取EditContext並手動調用NotifyFieldChanged

    [CascadingParameter] EditContext EditContext { get; set; } = default!;
    [Parameter] public Expression<Func<string>>? ValueExpression { get; set; }
    #endregion

    #region bindedValue
    [Parameter] public EventCallback<string> ValueChanged { get; set; }
    private string _value { set; get; } = "";
    [Parameter]
    public string Value
    {
        get => _value;
        set
        {
            if (_value == value) return;
            _value = value;
            ValueChanged.InvokeAsync(value);
            var fieldIdentifier = FieldIdentifier.Create(ValueExpression);
            EditContext.NotifyFieldChanged(fieldIdentifier);

        }
    }

選項 2(推薦):通過從 InputBase 繼承

您可以從InputBase<string>繼承並只實現TryParseValueFromString InputBase將為您完成工作,當您從InputBase繼承時,您將擁有ValueValueChangedEditContext等。

protected override bool TryParseValueFromString(string? value, out string result, [NotNullWhen(false)] out string? validationErrorMessage)
{
    result = value ?? "";
    validationErrorMessage = null;
    return true;
}

一般來說,接受的答案是正確的並且工作正常。 唯一需要添加的是代碼示例使用基於默認名稱約定的事件,例如: {PropertyName}Changed

[Parameter] public EventCallback<string> BindingValueChanged { get; set; }

但是,您可以覆蓋此命名約定@bind-{Property}:event="{EventCallbackName}"

<MyInputComponent @bind-BindingValue="model.Name" @bind-BindingValue:event="OnValueChanged"/>

.....

[Parameter] public EventCallback<string> OnValueChanged { get; set; }  

我花了一些時間才弄清楚dani herreras推薦的選項,所以我想為其他人提供一些清晰的信息。 我想將所有文本輸入更改為Bootstrap 5.0 浮動標簽 InputBase<string>繼承給了我們很多工作。 @CssClass自動負責應用驗證類,@ @CurrentValue為我們提供了組件的@bind-Value

輸入組件.razor

@using System.Linq.Expressions
@using Microsoft.AspNetCore.Components.Forms
@inherits InputBase<string>

<div class="form-floating mb-3">
  <input class="form-control @CssClass" id="@Id" @bind="@CurrentValue">
  <label for="@Id">@Label</label>
</div>

 <div class="form-control-validation">
    <ValidationMessage For="@ValidationFor" />
</div>

@code {

    [Parameter, EditorRequired] public Expression<Func<string>> ValidationFor { get; set; } = default!;
    [Parameter] public string? Id { get; set; }
    [Parameter] public string? Label { get; set; }

    protected override bool TryParseValueFromString(string? value, out string result, out string validationErrorMessage)
    {
        result = value;
        validationErrorMessage = null;
        return true;
    }
}

SomePage.razor

@using System.ComponentModel.DataAnnotations

<EditForm EditContext="@_editContext"  OnValidSubmit=@HandleValidSubmit>
    <DataAnnotationsValidator/>

    <button type="submit" class="btn btn-primary">Submit</button>
    <ValidationSummary />
    <InputComponent @bind-Value="person.Name" ValidationFor="@(()=>person.Name)" Label="Name" ></InputComponent>
    <p>Two way binded value: @person.Name</p>

</EditForm>
@code {

    private class ExamplePerson
    {
        [Required]
        public string Name { get; set; }
    }

    private ExamplePerson person { get; set; } = new ExamplePerson();

    private EditContext _editContext;

    protected override void OnInitialized()
    {
        _editContext = new(person);
        
    }
    private async void HandleValidSubmit()
    {

    }
}

此外,我們可以通過進行以下更改來使用 Bootstrap 5.0 class 名稱進行驗證。

protected override void OnInitialized()
{
    _editContext = new(person);
    _editContext.SetFieldCssClassProvider(new BootstrapValidationClassProvider());
}

public class BootstrapValidationClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
    {
        if (editContext == null)
            throw new ArgumentNullException(nameof(editContext));

        bool isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

        if (editContext.IsModified(fieldIdentifier))
            return isValid ? "is-valid" : "is-invalid";
            
        return isValid ? string.Empty : "is-invalid";
    }
}

將 Blazor 與 .NET7 結合使用,您可以執行以下操作:

我的自定義組件.Razor

<input type="text" @bind:get="BindingValue" @bind:set="SetAsync">

@code {


[Parameter]
public string BindingValue { get; set; }    
[Parameter]
public EventCallback<string> BindingValueChanged { get; set; }  

async Task SetAsync(string value)=> await BindingValueChanged.InvokeAsync(value);
}

}

然后你可以使用:

<MyCustomComponent @bind-BindingValue="whateverVariable" />                      

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM