ASP.NET Core Blazor veri bağlama

Not

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

Uyarı

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.

Bu makalede, uygulamalardaki Razor bileşenler ve DOM öğeleri için Blazor veri bağlama özellikleri açıklanmaktadır.

Bağlama özellikleri

Razorbileşenleri alan, özellik veya @bind ifade değeriyle RazorRazor yönerge özniteliğiyle veri bağlama özellikleri sağlar.

Aşağıdaki örnek bağlar:

  • <input> C# inputValue alanına bir öğe değeri.
  • C# <input> özelliğine InputValue ikinci bir öğe değeri.

Bir <input> öğe odağı kaybettiğinde, ilişkili alanı veya özelliği güncelleştirilir.

Bind.razor:

@page "/bind"

<PageTitle>Bind</PageTitle>

<h1>Bind Example</h1>

<p>
    <label>
        inputValue: 
        <input @bind="inputValue" />
    </label>
</p>

<p>
    <label>
        InputValue: 
        <input @bind="InputValue" />
    </label>
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string? inputValue;

    private string? InputValue { get; set; }
}
@page "/bind"

<PageTitle>Bind</PageTitle>

<h1>Bind Example</h1>

<p>
    <label>
        inputValue: 
        <input @bind="inputValue" />
    </label>
</p>

<p>
    <label>
        InputValue: 
        <input @bind="InputValue" />
    </label>
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string? inputValue;

    private string? InputValue { get; set; }
}
@page "/bind"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <input @bind="InputValue" />
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string? inputValue;

    private string? InputValue { get; set; }
}
@page "/bind"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <input @bind="InputValue" />
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string? inputValue;

    private string? InputValue { get; set; }
}
@page "/bind"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <input @bind="InputValue" />
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string inputValue;

    private string InputValue { get; set; }
}
@page "/bind"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <input @bind="InputValue" />
</p>

<ul>
    <li><code>inputValue</code>: @inputValue</li>
    <li><code>InputValue</code>: @InputValue</li>
</ul>

@code {
    private string inputValue;

    private string InputValue { get; set; }
}

Metin kutusu kullanıcı arabiriminde yalnızca bileşen işlendiğinde güncelleştirilir, alanın veya özelliğin değerinin değiştirilmesine yanıt olarak güncelleştirilmez. Bileşenler, olay işleyicisi kodu yürütülürken kendilerini işlediğinden, alan ve özellik güncelleştirmeleri genellikle bir olay işleyicisi tetiklendikten hemen sonra kullanıcı arabirimine yansıtılır.

Veri bağlamanın HTML'de nasıl oluştuğunu gösteren bir örnek olarak, aşağıdaki örnek özelliği ikinci InputValue öğenin <input> ve value özniteliklerine (onchange ) bağlarchange. Aşağıdaki örnekteki ikinci <input> öğe bir kavram gösterimidir ve bileşenlerdeki Razor verileri nasıl bağlamanız gerektiğini önermek için tasarlanmamıştır.

BindTheory.razor:

@page "/bind-theory"

<PageTitle>Bind Theory</PageTitle>

<h1>Bind Theory Example</h1>

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue" @onchange="@((ChangeEventArgs __e) =>
            InputValue = __e?.Value?.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-theory"

<PageTitle>Bind Theory</PageTitle>

<h1>Bind Theory Example</h1>

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue" @onchange="@((ChangeEventArgs __e) =>
            InputValue = __e?.Value?.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-theory"

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue"
            @onchange="@((ChangeEventArgs __e) => InputValue = __e?.Value?.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-theory"

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue"
            @onchange="@((ChangeEventArgs __e) => InputValue = __e?.Value?.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-theory"

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue"
            @onchange="@((ChangeEventArgs __e) => InputValue = __e.Value.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string InputValue { get; set; }
}
@page "/bind-theory"

<p>
    <label>
        Normal Blazor binding: 
        <input @bind="InputValue" />
    </label>
</p>

<p>
    <label>
        Demonstration of equivalent HTML binding: 
        <input value="@InputValue"
            @onchange="@((ChangeEventArgs __e) => InputValue = __e.Value.ToString())" />
    </label>
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string InputValue { get; set; }
}

BindTheory Bileşeni işlendiğinde, HTML tanıtım <input> öğesinin value özelliği InputValue özelliğinden kaynağını alır. Kullanıcı metin kutusuna bir değer girip öğe odağını değiştirdiğinde, onchange olay tetiklenir ve InputValue özellik değiştirilen değere ayarlanır. Gerçekte kod yürütme daha karmaşıktır çünkü @bind tür dönüştürmelerinin gerçekleştirildiği durumları işler. Genel olarak, @bind bir ifadenin geçerli değerini <input>'nin value özniteliğiyle ilişkilendirir ve kayıtlı işleyiciyi kullanarak değişiklikleri yönetir.

İle @bind varsayılan bağlama, change(onchange) DOM olayını kullanır. Bağlama, yer tutucunun input@bind:event="{EVENT}" veya {EVENT} (varsayılan) olduğu oninput özniteliği kullanılarak onchange DOM olayında da gerçekleşebilir.

Aşağıdaki örnek, öğenin oninput olayı tetiklendiğinde, InputValue özelliğini <input> öğesinin değerine bağlar. onchange Öğenin odağı kaybettiğinde tetiklenen olayın aksine, oninput metin kutusunun değeri değiştiğinde tetikler.

Page/BindEvent.razor:

@page "/bind-event"

<PageTitle>Bind Event</PageTitle>

<h1>Bind Event Example</h1>

<p>
    <label>
        InputValue: 
        <input @bind="InputValue" @bind:event="oninput" />
    </label>
    
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-event"

<PageTitle>Bind Event</PageTitle>

<h1>Bind Event Example</h1>

<p>
    <label>
        InputValue: 
        <input @bind="InputValue" @bind:event="oninput" />
    </label>
    
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-event"

<p>
    <input @bind="InputValue" @bind:event="oninput" />
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-event"

<p>
    <input @bind="InputValue" @bind:event="oninput" />
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string? InputValue { get; set; }
}
@page "/bind-event"

<p>
    <input @bind="InputValue" @bind:event="oninput" />
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string InputValue { get; set; }
}
@page "/bind-event"

<p>
    <input @bind="InputValue" @bind:event="oninput" />
</p>

<p>
    <code>InputValue</code>: @InputValue
</p>

@code {
    private string InputValue { get; set; }
}

Diğer DOM olaylarını bağlamak için aşağıdaki yaklaşımlardan birini kullanın:

Diğer DOM olaylarını bağlamak için temsilci olay işleyicilerini kullanın.

Razor öznitelik bağlama büyük/küçük harfe duyarlıdır:

  • @bind ve @bind:event geçerlidir.
  • @Bind / @Bind:Event (büyük harfler B ve E) veya @BIND/@BIND:EVENT (tüm büyük harfler) geçersizdir.

Zaman uyumsuz mantığı bağlamadan sonra yürütmek için, @bind:after="{DELEGATE}" kullanın; burada {DELEGATE} yer tutucusu bir C# temsilcisi (yöntem)dir. Atanan C# temsilcisi, bağlı değer senkronize olarak atanana kadar yürütülmez.

Bir olay geri çağırma parametresinin () ile kullanılması desteklenmez. Bunun yerine, Action veya Task değerini döndüren bir yöntemi @bind:after iletin.

Aşağıdaki örnekte:

  • Her <input> öğenin value alanı, searchText ile zaman uyumlu olarak bağlanmıştır.
  • PerformSearch yöntemi zaman uyumsuz olarak yürütülür:
    • Değer değiştirildikten sonra ilk kutu odak kaybettiğinde (onchange olayı).
    • İkinci kutudaki her tuş vuruşunun (oninput olay) ardından.
  • PerformSearch arama sonuçlarını döndürmek için zaman uyumsuz bir yöntemle (FetchAsync) bir hizmeti çağırır.
@inject ISearchService SearchService

<input @bind="searchText" @bind:after="PerformSearch" />
<input @bind="searchText" @bind:event="oninput" @bind:after="PerformSearch" />

@code {
    private string? searchText;
    private string[]? searchResult;

    private async Task PerformSearch() => 
        searchResult = await SearchService.FetchAsync(searchText);
}

Ek örnekler

BindAfter.razor:

@page "/bind-after"
@using Microsoft.AspNetCore.Components.Forms

<h1>Bind After Examples</h1>

<h2>Elements</h2>

<input type="text" @bind="text" @bind:after="() => { }" />

<input type="text" @bind="text" @bind:after="After" />

<input type="text" @bind="text" @bind:after="AfterAsync" />

<h2>Components</h2>

<InputText @bind-Value="text" @bind-Value:after="() => { }" />

<InputText @bind-Value="text" @bind-Value:after="After" />

<InputText @bind-Value="text" @bind-Value:after="AfterAsync" />

@code {
    private string text = "";

    private void After() {}
    private Task AfterAsync() { return Task.CompletedTask; }
}

Bileşen hakkında InputText daha fazla bilgi için bkz . ASP.NET Core Blazor giriş bileşenleri.

Bileşenler, @bind veya :get değiştiricisi olan bir :set öznitelik çifti tanımlayarak iki yönlü veri bağlamayı destekler. Aşağıdaki örneklerde yer alan {PARAMETER} yer tutucusu bir bileşen parametresini bağlamak için kullanılır:

  • @bind:get / @bind-{PARAMETER}:get: Bağlanacak değeri belirtir.
  • @bind:set / @bind-{PARAMETER}:set: Değer değiştiğinde için bir geri çağırma belirtir.

Değiştiriciler :get/:set her zaman birlikte kullanılır.

HTML öğelerine bağlama için, işleyicide değer değiştirildiğinde bile öğenin ilişkili bir değerle eşitlenmiş durumda kalmasını sağlamak için değiştiricileri kullanın:get/:set:<input>

<input @bind:get="inputValue" @bind:set="HandleValueChange" />

Not

.NET 7'nin yayımlanmasından önceki eski yaklaşım özniteliğini value ile kullanıyordu @onchange:

<input value="@inputValue" @onchange="HandleValueChange" />

Önceki yaklaşım, <input> öğesinin ilişkili değişkende tutulan değerden farklı bir değer görüntülemesine neden olabilecek senkronizasyon hatalarıyla sonuçlanabilir. Bu sorundan kaçınmak için :get/:set değiştiricilere geçin.

Bileşen parametreleri için, varsayımsal Child bir bileşen için aşağıdaki söz dizimleri işlevsel olarak eşdeğerdir:

<Child Value="@inputValue" ValueChanged="@(v => inputValue = v)" />
<Child @bind-Value:get="inputValue" @bind-Value:set="@(v => inputValue = v)" />

Değiştirici bağlama ile :get/:set , dom'a uygulanmadan önce bir değer değişikliğine tepki verebilir ve gerekirse uygulanan değeri değiştirebilirsiniz. @bind:event="{EVENT}" yer tutucusunun bir DOM olayı olarak kullanıldığı {EVENT} öznitelik bağlama durumunda, DOM güncellendikten sonra bildirimi alırsınız ve bağlama esnasında uygulanan değerin değiştirilmesi mümkün değildir.

Aşağıdaki bileşen, öğeleri ve bileşen için söz dizimini, formlarının zaman uyumlu () ve uyumsuz () senaryolarda nasıl kullanıldığını göstermektedir.

BindGetSet.razor:

@page "/bind-get-set"
@using Microsoft.AspNetCore.Components.Forms

<h1>Bind Get Set Examples</h1>

<h2>Elements</h2>

<input type="text" @bind:get="text" @bind:set="(value) => { text = value; }" />
<input type="text" @bind:get="text" @bind:set="Set" />
<input type="text" @bind:get="text" @bind:set="SetAsync" />

<h2>Components</h2>

<InputText @bind-Value:get="text" @bind-Value:set="(value) => { text = value; }" />
<InputText @bind-Value:get="text" @bind-Value:set="Set" />
<InputText @bind-Value:get="text" @bind-Value:set="SetAsync" />

@code {
    private string text = string.Empty;

    private void Set(string value)
    {
        text = value;
    }

    private Task SetAsync(string value)
    {
        text = value;
        return Task.CompletedTask;
    }
}

Bileşen hakkında InputText daha fazla bilgi için bkz . ASP.NET Core Blazor giriş bileşenleri.

Başka bir örnek kullanım için, :get ve :set değiştiricilerini, bu makalenin devamında yer alan İkiden fazla bileşen arasında bağlama bölümüne bakın.

Razor öznitelik bağlama büyük/küçük harfe duyarlıdır:

  • @bind, @bind:eventve @bind:after geçerli.
  • @Bind / @bind:Event / @bind:aftEr(büyük harfler) veya @BIND/@BIND:EVENT/@BIND:AFTER(tüm büyük harfler) geçersizdir.

Değiştiricileri kullanma @bind:get/@bind:set ve iki yönlü veri bağlama için olay işleyicilerinden kaçınma

olay işleyicisi ile iki yönlü veri bağlaması uygulanamaz. İki yönlü veri bağlama için değiştiricileri kullanın :get/:set .

Olay işleyicisi kullanarak iki yönlü veri bağlama için aşağıdaki işlevsiz yaklaşımı göz önünde bulundurun:

<p>
    <input value="@inputValue" @oninput="OnInput" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private string? inputValue;

    private void OnInput(ChangeEventArgs args)
    {
        var newValue = args.Value?.ToString() ?? string.Empty;

        inputValue = newValue.Length > 4 ? "Long!" : newValue;
    }
}

Olay işleyicisi, dördüncü karakter sağlandıktan sonra, OnInput'in değerini inputValueLong! olarak günceller. Ancak kullanıcı, kullanıcı arabirimindeki öğe değerine karakter eklemeye devam edebilir. inputValue'nin değeri, her tuş vuruşuyla öğenin değerine geri bağlanmaz. Yukarıdaki örnek yalnızca tek yönlü veri bağlama özelliğine sahiptir.

Bu davranışın nedeni, kodunuzun Blazor olay işleyicisindeki değerini inputValue değiştirmeyi amaçladığının farkında olmamanızdır. Blazor dom öğesi değerleri ve .NET değişken değerleri, söz dizimi ile @bind bağlı olmadığı sürece eşleşecek şekilde zorlamaya çalışmaz. önceki sürümlerinde Blazor, iki yönlü veri bağlama, öğesini bir özelliğe bağlayarak ve özelliğin değerini ayarlayıcısıyla denetleyerek uygulanır. .NET 7 veya sonraki sürümlerindeki ASP.NET Core'da, :get/:set sonraki örnekte gösterildiği gibi iki yönlü veri bağlama uygulamak için değiştirici söz dizimi kullanılır.

İki yönlü veri bağlama için :get/:set kullanarak aşağıdaki doğru yaklaşımı göz önünde bulundurun.

<p>
    <input @bind:event="oninput" @bind:get="inputValue" @bind:set="OnInput" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private string? inputValue;

    private void OnInput(string value)
    {
        var newValue = value ?? string.Empty;

        inputValue = newValue.Length > 4 ? "Long!" : newValue;
    }
}

Değiştiriciler :get/:set kullanıldığında, hem inputValue öğesinin :set temel değerini denetler hem de inputValue değerini, :get öğesinin değeriyle bağlar. Yukarıdaki örnekte, iki yönlü veri bağlama uygulamak için doğru yaklaşım gösterilmektedir.

C# get ve set erişimcilerle bir özelliğe bağlama

C# get ve set erişimciler , aşağıdaki DecimalBinding bileşenin gösterdiği gibi özel bağlama biçimi davranışı oluşturmak için kullanılabilir. Bileşen, en fazla üç ondalık basamağa sahip pozitif veya negatif bir ondalığı, bir özellik (string) aracılığıyla bir <input> öğesine bağlar.

DecimalBinding.razor:

@page "/decimal-binding"
@using System.Globalization

<PageTitle>Decimal Binding</PageTitle>

<h1>Decimal Binding Example</h1>

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}
@page "/decimal-binding"
@using System.Globalization

<PageTitle>Decimal Binding</PageTitle>

<h1>Decimal Binding Example</h1>

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}
@page "/decimal-binding"
@using System.Globalization

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}
@page "/decimal-binding"
@using System.Globalization

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}
@page "/decimal-binding"
@using System.Globalization

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}
@page "/decimal-binding"
@using System.Globalization

<p>
    <label>
        Decimal value (±0.000 format):
        <input @bind="DecimalValue" />
    </label>
</p>

<p>
    <code>decimalValue</code>: @decimalValue
</p>

@code {
    private decimal decimalValue = 1.1M;
    private NumberStyles style = 
        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

    private string DecimalValue
    {
        get => decimalValue.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                decimalValue = Math.Round(number, 3);
            }
        }
    }
}

Not

Birden çok bileşen arasında, get/set erişimcilerine sahip bir özelliğe çift yönlü bağlama, özelliğin ayarlayıcısında Task tarafından döndürülen EventCallback.InvokeAsync değerinin atılmasını gerektirir. İki yönlü veri bağlama için değiştiricileri kullanmanızı @bind:get/@bind:set öneririz. Daha fazla bilgi için bu makalenin önceki bölümlerinde kılavuzuna bakın.

.NET 6 veya önceki sürümlerinde EventCallback.InvokeAsync tarafından döndürülen Task'ın, @bind:get/@bind:set değiştiricileri bir çerçeve özelliği haline gelmeden önce nasıl atıldığını gösteren bir örnek görmek için bu makalenin .NET 6 sürümündeki Bind across more than two components bölümünün NestedChild bileşenine bakın.

Not

Erişimcileri olan get/set bir özelliğe iki yönlü bağlama, EventCallback.InvokeAsync tarafından döndürülen Task'ın atılmasını gerektirir. Örneğin, ikiden fazla bileşen arasında bağlama bileşenini bölümüne bakın. .NET 7 veya sonraki sürümlerinde iki yönlü veri bağlama için, bu makalenin .NET 7 veya sonraki sürümlerinde açıklanan değiştiricileri kullanmanızı @bind:get/@bind:set öneririz.

Öğelerle birden çok seçenek seçimi <select>

Bağlama, multiple seçenek seçimini <select> öğelerle destekler. Olay, @onchange seçilen öğelerin bir dizisini olay bağımsız değişkenleri (ChangeEventArgs) aracılığıyla sağlar. Değer bir dizi türüne bağlı olmalıdır.

BindMultipleInput.razor:

@page "/bind-multiple-input"

<h1>Bind Multiple <code>input</code>Example</h1>

<p>
    <label>
        Select one or more cars: 
        <select @onchange="SelectedCarsChanged" multiple>
            <option value="audi">Audi</option>
            <option value="jeep">Jeep</option>
            <option value="opel">Opel</option>
            <option value="saab">Saab</option>
            <option value="volvo">Volvo</option>
        </select>
    </label>
</p>

<p>
    Selected Cars: @string.Join(", ", SelectedCars)
</p>

<p>
    <label>
        Select one or more cities: 
        <select @bind="SelectedCities" multiple>
            <option value="bal">Baltimore</option>
            <option value="la">Los Angeles</option>
            <option value="pdx">Portland</option>
            <option value="sf">San Francisco</option>
            <option value="sea">Seattle</option>
        </select>
    </label>
</p>

<span>
    Selected Cities: @string.Join(", ", SelectedCities)
</span>

@code {
    public string[] SelectedCars { get; set; } = [];
    public string[] SelectedCities { get; set; } = [ "bal", "sea" ];

    private void SelectedCarsChanged(ChangeEventArgs e)
    {
        if (e.Value is not null)
        {
            SelectedCars = (string[])e.Value;
        }
    }
}
@page "/bind-multiple-input"

<h1>Bind Multiple <code>input</code>Example</h1>

<p>
    <label>
        Select one or more cars: 
        <select @onchange="SelectedCarsChanged" multiple>
            <option value="audi">Audi</option>
            <option value="jeep">Jeep</option>
            <option value="opel">Opel</option>
            <option value="saab">Saab</option>
            <option value="volvo">Volvo</option>
        </select>
    </label>
</p>

<p>
    Selected Cars: @string.Join(", ", SelectedCars)
</p>

<p>
    <label>
        Select one or more cities: 
        <select @bind="SelectedCities" multiple>
            <option value="bal">Baltimore</option>
            <option value="la">Los Angeles</option>
            <option value="pdx">Portland</option>
            <option value="sf">San Francisco</option>
            <option value="sea">Seattle</option>
        </select>
    </label>
</p>

<span>
    Selected Cities: @string.Join(", ", SelectedCities)
</span>

@code {
    public string[] SelectedCars { get; set; } = new string[] { };
    public string[] SelectedCities { get; set; } = new[] { "bal", "sea" };

    private void SelectedCarsChanged(ChangeEventArgs e)
    {
        if (e.Value is not null)
        {
            SelectedCars = (string[])e.Value;
        }
    }
}

Boş dizelerin ve null değerlerin veri bağlamada nasıl işleneceğini öğrenmek için C# nesne <select> değerlerine öğe seçeneklerini bağlama null bölümüne bakın.

Öğe seçeneklerini C# nesne <select> değerlerine bağlama null

Öğe seçenek değerini C# nesne <select> değeri olarak temsil null etmenin mantıklı bir yolu yoktur, çünkü:

  • HTML öznitelikleri null değerlerine sahip olamaz. HTML'deki null için en yakın eşdeğer, <option> öğesinden value HTML özniteliğinin olmamasıdır.
  • Özniteliği olmayan bir <option> seçerken, tarayıcı değeri o value'in metin içeriği olarak değerlendirir.

Çerçeve, Blazor aşağıdakileri içereceğinden varsayılan davranışı gizlemeye çalışmaz:

  • Çerçevede özel durumlar için geçici çözümler zinciri oluşturma.
  • Mevcut çerçeve davranışında köklü değişiklikler.

HTML'deki en makul null eşdeğer boş bir dizedirvalue. Çerçeve, iki yönlü bağlama için <select> değerinin boş bir dizeye dönüşümlerini Blazornull olarak ele alır.

Ayrıştırılamaz değerler

Kullanıcı veriye bağlı bir öğeye ayrıştırılamaz bir değer sağladığında, bağlama olayı tetiklendiğinde ayrıştırılamaz değer otomatik olarak önceki değerine geri döndürülür.

Bir öğenin başlangıç değeri <input>olan bir int türe bağlı olduğu 123 aşağıdaki bileşeni göz önünde bulundurun.

UnparsableValues.razor:

@page "/unparsable-values"

<PageTitle>Unparsable Values</PageTitle>

<h1>Unparsable Values Example</h1>

<p>
    <label>
        inputValue: 
        <input @bind="inputValue" />
    </label>
    
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}
@page "/unparsable-values"

<PageTitle>Unparsable Values</PageTitle>

<h1>Unparsable Values Example</h1>

<p>
    <label>
        inputValue: 
        <input @bind="inputValue" />
    </label>
    
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}
@page "/unparseable-values"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}
@page "/unparseable-values"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}
@page "/unparseable-values"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}
@page "/unparseable-values"

<p>
    <input @bind="inputValue" />
</p>

<p>
    <code>inputValue</code>: @inputValue
</p>

@code {
    private int inputValue = 123;
}

Bağlama, öğenin onchange olayı için geçerlidir. Kullanıcı metin kutusunun girdisinin değerini 123.45 olarak günceller ve odağı değiştirirse, onchange tetiklendiğinde, öğenin değeri 123 olarak geri döndürülür. 123.45 değeri, özgün 123 değeri lehine reddedildiğinde, kullanıcı değerinin kabul edilmediğini anlar.

oninput olayı (@bind:event="oninput") için, ayrıştırılamaz bir değer getiren herhangi bir tuş vuruşunun ardından bir değer geri dönüşü gerçekleşir. oninput etkinliği bir bağlı tür int ile hedeflenirken, kullanıcının nokta (.) karakteri yazması engellenir. Nokta (.) karakteri hemen kaldırılır, bu nedenle kullanıcı yalnızca tam sayılara izin verildiğini hemen geri bildirim verir. oninput olayında değerin geri döndürülmesinin ideal olmadığı senaryolar vardır, örneğin kullanıcının ayrıştırılamaz bir <input> değeri temizlemesine izin verilmesi gerektiği durumlar. Alternatifler şunlardır:

  • oninput olayını kullanmayın. Öğe odağı kaybedene kadar geçersiz bir değerin geri döndürülmediği varsayılan onchange olayı kullanın.
  • int? veya string gibi null atanabilir bir türe bağlanarak, @bind:get/@bind:set değiştiricilerini (bu makalenin başlarında açıklanmıştır) kullanın veya geçersiz girişleri işlemek için özel get ve set erişimci mantığına sahip bir özelliğe bağlanın.
  • Form doğrulaması ile giriş bileşeni, örneğin InputNumber<TValue> veya InputDate<TValue>, kullanın. Form doğrulama bileşenleriyle birlikte giriş bileşenleri, geçersiz girişleri yönetmek için yerleşik destek sağlar:
    • Kullanıcının geçersiz giriş sağlamasına ve ilişkili EditContextüzerinde doğrulama hataları almasına izin ver.
    • Kullanıcının ek web formu verileri girmesini engellemeden kullanıcı arabiriminde doğrulama hatalarını görüntüleyin.

Dizeleri biçimlendirme

Veri bağlama, tek bir DateTime biçim dizesi kullanarak @bind:format="{FORMAT STRING}" ile çalışır; burada {FORMAT STRING} yer tutucu biçim dizesidir. Para birimi veya sayı biçimleri gibi diğer biçim ifadeleri şu anda kullanılamamaktadır, ancak gelecekteki bir sürüme eklenebilir.

DateBinding.razor:

@page "/date-binding"

<PageTitle>Date Binding</PageTitle>

<h1>Date Binding Example</h1>

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new(2020, 1, 1);
}
@page "/date-binding"

<PageTitle>Date Binding</PageTitle>

<h1>Date Binding Example</h1>

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new(2020, 1, 1);
}
@page "/date-binding"

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new(2020, 1, 1);
}
@page "/date-binding"

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new(2020, 1, 1);
}
@page "/date-binding"

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new(2020, 1, 1);
}
@page "/date-binding"

<p>
    <label>
        <code>yyyy-MM-dd</code> format:
        <input @bind="startDate" @bind:format="yyyy-MM-dd" />
    </label>
</p>

<p>
    <code>startDate</code>: @startDate
</p>

@code {
    private DateTime startDate = new DateTime(2020, 1, 1);
}

Yukarıdaki kodda <input> , öğenin alan türü (type özniteliği) varsayılan olarak olur text.

Null yapılabilir System.DateTime ve System.DateTimeOffset desteklenir.

private DateTime? date;
private DateTimeOffset? dateOffset;

Blazor tarihleri biçimlendirmek için yerleşik desteğe sahip olduğundan, date alan türü için bir biçim belirtilmesi önerilmez. Öneriye rağmen, yalnızca bir biçim, date alan türüyle sağlandığında bağlamanın doğru çalışması için yyyy-MM-dd tarih biçimini kullanın:

<input type="date" @bind="startDate" @bind:format="yyyy-MM-dd">

Bileşen parametreleriyle bağlama

Yaygın bir senaryo, bir alt bileşenin özelliğini üst bileşenindeki bir özelliğe bağlamaktır. Birden çok bağlama düzeyi aynı anda gerçekleştiğinden bu senaryo zincirleme bağlama olarak adlandırılır.

Bir alt bileşende @bind söz dizimi kullanarak zincirlenmiş bağlamalar uygulayamazsınız. Üst öğedeki özelliğin alt bileşenden güncelleştirilmesini desteklemek için bir olay işleyicisi ve değeri ayrı olarak belirtilmelidir. Üst bileşen, alt bileşenle veri bağlamayı ayarlamak için @bind söz dizimini kullanmaya devam ediyor.

Aşağıdaki ChildBind bileşeni bir Year bileşen parametresine ve bir EventCallback<TValue>'ye sahiptir. Kural gereği, EventCallback<TValue> parametresi için "Changed" soneki ile bileşen parametre adı olarak adlandırılmalıdır. Adlandırma söz dizimi, {PARAMETER NAME}Changedyer tutucunun {PARAMETER NAME} parametre adı olduğu şeklindedir. Aşağıdaki örnekte, EventCallback<TValue> adı YearChanged olarak verilmiştir.

EventCallback.InvokeAsync sağlanan bağımsız değişkenle bağlamayla ilişkilendirilmiş temsilciyi çağırır ve değişen özellik için bir olay bildirimi gönderir.

ChildBind.razor:

<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild() => 
        await YearChanged.InvokeAsync(Random.Shared.Next(1950, 2021));
}
<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild() => 
        await YearChanged.InvokeAsync(Random.Shared.Next(1950, 2021));
}
<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild()
    {
        await YearChanged.InvokeAsync(Random.Shared.Next(1950, 2021));
    }
}
<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild()
    {
        await YearChanged.InvokeAsync(Random.Shared.Next(1950, 2021));
    }
}
<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    private Random r = new();

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild()
    {
        await YearChanged.InvokeAsync(r.Next(1950, 2021));
    }
}
<div class="card bg-light mt-3" style="width:18rem ">
    <div class="card-body">
        <h3 class="card-title">ChildBind Component</h3>
        <p class="card-text">
            Child <code>Year</code>: @Year
        </p>
        <button @onclick="UpdateYearFromChild">Update Year from Child</button>
    </div>
</div>

@code {
    private Random r = new Random();

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    private async Task UpdateYearFromChild()
    {
        await YearChanged.InvokeAsync(r.Next(1950, 2021));
    }
}

ve EventCallback<TValue>olayları hakkında daha fazla bilgi için ASP.NET Core olay işlemeBlazorEventCallback bölümüne bakın.

Aşağıdaki Parent1 bileşende year , alan alt bileşenin Year parametresine bağlıdır. Year parametresi, türü Year parametresiyle eşleşen bir YearChanged olayına sahip olduğundan bağlanabilir.

Parent1.razor:

@page "/parent-1"

<PageTitle>Parent 1</PageTitle>

<h1>Parent Example 1</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private int year = 1979;

    private void UpdateYear() => year = Random.Shared.Next(1950, 2021);
}
@page "/parent-1"

<PageTitle>Parent 1</PageTitle>

<h1>Parent Example 1</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private int year = 1979;

    private void UpdateYear() => year = Random.Shared.Next(1950, 2021);
}
@page "/parent-1"

<h1>Parent Component</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private int year = 1979;

    private void UpdateYear()
    {
        year = Random.Shared.Next(1950, 2021);
    }
}
@page "/parent-1"

<h1>Parent Component</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private int year = 1979;

    private void UpdateYear()
    {
        year = Random.Shared.Next(1950, 2021);
    }
}
@page "/parent-1"

<h1>Parent Component</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private Random r = new();
    private int year = 1979;

    private void UpdateYear()
    {
        year = r.Next(1950, 2021);
    }
}
@page "/parent-1"

<h1>Parent Component</h1>

<p>Parent <code>year</code>: @year</p>

<button @onclick="UpdateYear">Update Parent <code>year</code></button>

<ChildBind @bind-Year="year" />

@code {
    private Random r = new Random();
    private int year = 1979;

    private void UpdateYear()
    {
        year = r.Next(1950, 2021);
    }
}

Bileşen parametresi bağlaması @bind:after olaylarını da tetikleyebilir. Aşağıdaki örnekte, YearUpdated yöntemi, Year bileşen parametresi bağlandıktan sonra zaman uyumsuz olarak yürütülür.

<ChildBind @bind-Year="year" @bind-Year:after="YearUpdated" />

@code {
    ...

    private async Task YearUpdated()
    {
        ... = await ...;
    }
}

Genel olarak bir özellik, işleyiciye atanmış bir @bind-{PROPERTY}:event öznitelik eklenerek ilgili olay işleyicisine bağlanabilir ve burada {PROPERTY} yer tutucu özelliğidir. <ChildBind @bind-Year="year" /> yazmakla eşdeğerdir:

<ChildBind @bind-Year="year" @bind-Year:event="YearChanged" />

Daha karmaşık ve gerçek bir örnekte aşağıdaki PasswordEntry bileşen:

  • Bir <input> öğenin değerini bir password alana ayarlar.
  • Bir Password özelliğindeki değişiklikleri, alt bileşenin password alanının geçerli değerini argüman olarak alarak bir EventCallback üst bileşene iletir.
  • onclick olayını ToggleShowPassword yöntemini tetiklemek için kullanır. Daha fazla bilgi için bkz . ASP.NET Core Blazor olay işleme.

Uyarı

Uygulama gizli dizilerini, bağlantı dizesi'leri, kimlik bilgilerini, parolaları, kişisel kimlik numaralarını (PIN'ler), özel C#/.NET kodunu veya özel anahtarları/belirteçleri her zaman güvenli olmayan istemci tarafı kodunda depolamayın. Test/hazırlama ve üretim ortamlarında, sunucu tarafı Blazor kod ve web API'leri, proje kodu veya yapılandırma dosyalarında kimlik bilgilerinin korunmasını önleyen güvenli kimlik doğrulama akışları kullanmalıdır. Yerel geliştirme testlerinin dışında, ortam değişkenleri en güvenli yaklaşım olmadığından hassas verileri depolamak için ortam değişkenlerinin kullanılmasından kaçınmanızı öneririz. Yerel geliştirme testinde gizli verilerin güvenliğini sağlamak için Gizli Dizi Yöneticisi aracı önerilir. Daha fazla bilgi için bkz . Hassas verileri ve kimlik bilgilerini güvenli bir şekilde koruma.

PasswordEntry.razor:

<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string? password;

    [Parameter]
    public string? Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string? password;

    [Parameter]
    public string? Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string? password;

    [Parameter]
    public string? Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string? password;

    [Parameter]
    public string? Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string password;

    [Parameter]
    public string Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e.Value.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
        </p>
    </div>
</div>

@code {
    private string password;

    [Parameter]
    public string Password { get; set; }

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

    private async Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e.Value.ToString();

        await PasswordChanged.InvokeAsync(password);
    }
}

Bileşen PasswordEntry , aşağıdaki PasswordBinding bileşen örneği gibi başka bir bileşende kullanılır.

PasswordBinding.razor:

@page "/password-binding"

<PageTitle>Password Binding</PageTitle>

<h1>Password Binding Example</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}
@page "/password-binding"

<PageTitle>Password Binding</PageTitle>

<h1>Password Binding Example</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}
@page "/password-binding"

<h1>Password Binding</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}
@page "/password-binding"

<h1>Password Binding</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}
@page "/password-binding"

<h1>Password Binding</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}
@page "/password-binding"

<h1>Password Binding</h1>

<PasswordEntry @bind-Password="password" />

<p>
    <code>password</code>: @password
</p>

@code {
    private string password = "Not set";
}

PasswordBinding bileşeni ilk defa render edildiğinde, password değeri Not set kullanıcının arabiriminde görüntülenir. İlk işlemeden sonra, password değeri Password bileşen parametre değerinde PasswordEntry yapılan değişiklikleri yansıtır.

Not

Yukarıdaki örnek, parolayı alt PasswordEntry bileşenden üst PasswordBinding bileşene tek yönlü bağlar. Uygulamanın yalnızca parolayı üst öğeye ileten ve uygulama içinde yeniden kullanılabilen ortak bir parola giriş bileşenine sahip olması hedeflendiğinde, bu senaryoda iki yönlü bağlama gerekli değildir. Doğrudan alt bileşenin parametresine yazmadan iki yönlü bağlamaya izin veren bir yaklaşım için, bu makalenin İkiden fazla bileşen arasında bağlama bölümündeki bileşen örneğine bakınNestedChild.

Hata işleyicide denetimler yapın veya hataları yakalayın. Aşağıdaki düzeltilmiş PasswordEntry bileşen, parolanın değerinde bir alan kullanılıyorsa kullanıcıya anında geri bildirim sağlar.

PasswordEntry.razor:

<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string? password;
    private string? validationMessage;

    [Parameter]
    public string? Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        if (password != null && password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string? password;
    private string? validationMessage;

    [Parameter]
    public string? Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        if (password != null && password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string? password;
    private string? validationMessage;

    [Parameter]
    public string? Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        if (password != null && password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}

Aşağıdaki örnekte, Password bileşen parametresi bağlandıktan sonra PasswordUpdated yöntemi eşzamansız olarak yürütülür.

<PasswordEntry @bind-Password="password" @bind-Password:after="PasswordUpdated" />
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string? password;
    private string? validationMessage;

    [Parameter]
    public string? Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e?.Value?.ToString();

        if (password != null && password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e.Value.ToString();

        if (password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}
<div class="card bg-light mt-3" style="width:22rem ">
    <div class="card-body">
        <h3 class="card-title">Password Component</h3>
        <p class="card-text">
            <label>
                Password:
                <input @oninput="OnPasswordChanged" required type="password"
                    value="@password" />
            </label>
            <span class="text-danger">@validationMessage</span>
        </p>
    </div>
</div>

@code {
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password { get; set; }

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

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        password = e.Value.ToString();

        if (password.Contains(' '))
        {
            validationMessage = "Spaces not allowed!";

            return Task.CompletedTask;
        }
        else
        {
            validationMessage = string.Empty;

            return PasswordChanged.InvokeAsync(password);
        }
    }
}

İkiden fazla bileşen arasında bağlama

parametreleri istediğiniz sayıda iç içe bileşen aracılığıyla bağlayabilirsiniz, ancak tek yönlü veri akışına saygı göstermelisiniz:

  • Değişiklik bildirimleri hiyerarşiyi yukarı taşır.
  • Yeni parametre değerleri hiyerarşide aşağı doğru akar.

Yaygın ve önerilen bir yaklaşım, aşağıdaki örnekte gösterildiği gibi hangi durumun güncelleştirilmesi gerektiği konusunda herhangi bir karışıklığı önlemek için yalnızca temel alınan verileri üst bileşende depolamaktır.

Parent2.razor:

@page "/parent-2"

<PageTitle>Parent 2</PageTitle>

<h1>Parent Example 2</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue() => parentMessage = $"Set in Parent {DateTime.Now}";
}
@page "/parent-2"

<PageTitle>Parent 2</PageTitle>

<h1>Parent Example 2</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue() => parentMessage = $"Set in Parent {DateTime.Now}";
}
@page "/parent-2"

<h1>Parent Component</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue()
    {
        parentMessage = $"Set in Parent {DateTime.Now}";
    }
}
@page "/parent-2"

<h1>Parent Component</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue()
    {
        parentMessage = $"Set in Parent {DateTime.Now}";
    }
}
@page "/parent-2"

<h1>Parent Component</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue()
    {
        parentMessage = $"Set in Parent {DateTime.Now}";
    }
}
@page "/parent-2"

<h1>Parent Component</h1>

<p>Parent Message: <b>@parentMessage</b></p>

<p>
    <button @onclick="ChangeValue">Change from Parent</button>
</p>

<NestedChild @bind-ChildMessage="parentMessage" />

@code {
    private string parentMessage = "Initial value set in Parent";

    private void ChangeValue()
    {
        parentMessage = $"Set in Parent {DateTime.Now}";
    }
}

Aşağıdaki NestedChild bileşeninde NestedGrandchild bileşeni:

  • ChildMessage, @bind:get söz dizimi ile GrandchildMessage'e atanır.
  • GrandchildMessageChildMessageChanged ile çalıştırıldığında @bind:set söz dizimiyle günceller.

.NET 7'nin yayımlanmasından önce, bileşenler arasında iki yönlü bağlama, bir ayarlayıcısında get tarafından döndürülen /'ü atan üçüncü bir özellik ile birlikte setTaskEventCallback.InvokeAsync erişimcilerini kullanır. değiştiriciler bir çerçeve özelliği haline gelmeden önce .NET 6 veya önceki sürümlerine yönelik bu yaklaşımın bir örneğini görmek için,bu makalenin .NET 6 sürümünde bu bölümün bileşenine bakın.

Bir bileşen parametresinin değerini doğrudan değiştirmekten kaçınmanın nedeni, alt bileşenin üst bileşenin durumunu etkili bir şekilde değiştirmesidir. Bu, Blazor'nin değişiklik algılama sürecini etkileyebilir ve parametreler giriş olarak kullanılmak üzere tasarlandıkları için, bunların değişken bir durum olmaması gerektiğinden ekstra işleme döngülerini tetikleyebilir. Verilerin bileşenler arasında geçirildiği zincirlenmiş senaryolarda, bir bileşen parametresine doğrudan yazmak, uygulamayı kilitleyen sonsuz rerender'lar gibi istenmeyen etkilere yol açabilir.

@bind:get / @bind:set söz dizimi şunları yapmanızı sağlar:

  • .NET 7'nin yayımlanmasından önce gerekli olan zincirlenmiş bileşenler arasında yalnızca değerleri ve geri çağırmaları iletmek için var olan ek bir özellik oluşturmaktan kaçının.
  • Değerleri uygulanmadan önce yakala ve dönüştür.
  • İki yönlü bağlamayı desteklerken parametreyi alt öğede değişmez tutun.

Yararlı bir benzetme, HTML'nin <input> aşağıdaki değer durumlarını izleyen öğesidir:

  • defaultValue: Ebeveynden alınan bir bileşen parametresi gibi.
  • value: Bileşenin içindeki mevcut durum gibi.

Eğer defaultValue doğrudan değiştirirseniz, sözleşmeyi bozuyorsunuz. Bunun yerine, bu durumlar ayrı tutulur ve öğenin ilk işlenmesinden sonra yalnızca value, kontrol edilen yöntemler aracılığıyla güncelleştirilir. Aynı mantık bileşen parametreleri için de geçerlidir ve söz diziminin kullanılması @bind:get/@bind:set , doğrudan bileşen parametrelerine yazmayla ilişkili istenmeyen işleme efektlerini önler.

NestedChild.razor:

<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage:get="ChildMessage" 
        @bind-GrandchildMessage:set="ChildMessageChanged" />
</div>

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

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

    private async Task ChangeValue() => 
        await ChildMessageChanged.InvokeAsync($"Set in Child {DateTime.Now}");
}
<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage:get="ChildMessage" 
        @bind-GrandchildMessage:set="ChildMessageChanged" />
</div>

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

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

    private async Task ChangeValue() => 
        await ChildMessageChanged.InvokeAsync($"Set in Child {DateTime.Now}");
}
<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage:get="ChildMessage" 
        @bind-GrandchildMessage:set="ChildMessageChanged" />
</div>

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

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

    private async Task ChangeValue()
    {
        await ChildMessageChanged.InvokeAsync(
            $"Set in Child {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage="BoundValue" />
</div>

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

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

    private string BoundValue
    {
        get => ChildMessage ?? string.Empty;
        set => ChildMessageChanged.InvokeAsync(value);
    }

    private async Task ChangeValue()
    {
        await ChildMessageChanged.InvokeAsync(
            $"Set in Child {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage="BoundValue" />
</div>

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

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

    private string BoundValue
    {
        get => ChildMessage;
        set => ChildMessageChanged.InvokeAsync(value);
    }

    private async Task ChangeValue()
    {
        await ChildMessageChanged.InvokeAsync(
            $"Set in Child {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h2>Child Component</h2>

    <p>Child Message: <b>@ChildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Child</button>
    </p>

    <NestedGrandchild @bind-GrandchildMessage="BoundValue" />
</div>

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

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

    private string BoundValue
    {
        get => ChildMessage;
        set => ChildMessageChanged.InvokeAsync(value);
    }

    private async Task ChangeValue()
    {
        await ChildMessageChanged.InvokeAsync(
            $"Set in Child {DateTime.Now}");
    }
}

Uyarı

Genel olarak, doğrudan kendi bileşen parametrelerine yazan bileşenler oluşturmaktan kaçının. Önceki NestedChild bileşen, doğrudan BoundValue parametresine yazmak yerine bir ChildMessage özelliği kullanır. Daha fazla bilgi için bkz . ASP.NET Core'da Blazorparametrelerin üzerine yazmaktan kaçının.

NestedGrandchild.razor:

<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue() => 
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
}
<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue() => 
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
}
<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue()
    {
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue()
    {
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue()
    {
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
    }
}
<div class="border rounded m-1 p-1">
    <h3>Grandchild Component</h3>

    <p>Grandchild Message: <b>@GrandchildMessage</b></p>

    <p>
        <button @onclick="ChangeValue">Change from Grandchild</button>
    </p>
</div>

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

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

    private async Task ChangeValue()
    {
        await GrandchildMessageChanged.InvokeAsync(
            $"Set in Grandchild {DateTime.Now}");
    }
}

Bellekte ve iç içe olması gerekmeyen bileşenler arasında veri paylaşmaya uygun alternatif bir yaklaşım için bkz . ASP.NET Çekirdek Blazor durum yönetimine genel bakış.

Bağlanmış alan veya özellik ifade ağacı

Bağlamayla daha derin etkileşimleri kolaylaştırmak için, Blazor ilişkili bir alanın veya özelliğin ifade ağacını yakalamanıza olanak tanır. Bu, alan veya özellik adına Expression son eki eklenerek bir özellik tanımlanarak elde edilir. {FIELD OR PROPERTY NAME} adlı herhangi bir alan veya özellik için, buna karşılık gelen ifade ağacı özelliği {FIELD OR PROPERTY NAME}Expression olarak adlandırılır.

Aşağıdaki ChildParameterExpression bileşen, ifadenin Year modelini ve alan adını tanımlar. FieldIdentifier, model ve alan adını elde etmek için kullanılan ve düzenlenebilecek tek bir alanı benzersiz olarak tanımlayan bir yapıdır. Bu, model nesnesinde bir özelliğe karşılık gelebilir veya başka bir adlandırılmış değer olabilir. Bir parametrenin ifadesinin kullanılması, Microsoft Blazor belgelerinde yer almayan ancak çok sayıda üçüncü taraf kaynağı tarafından ele alınan özel doğrulama bileşenleri oluştururken kullanışlıdır.

ChildParameterExpression.razor:

@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized() => 
        yearField = FieldIdentifier.Create(YearExpression);
}
@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized() => 
        yearField = FieldIdentifier.Create(YearExpression);
}
@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized()
    {
        yearField = FieldIdentifier.Create(YearExpression);
    }
}
@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized()
    {
        yearField = FieldIdentifier.Create(YearExpression);
    }
}
@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized()
    {
        yearField = FieldIdentifier.Create(YearExpression);
    }
}
@using System.Linq.Expressions

<ul>
    <li>Year model: @yearField.Model</li>
    <li>Year field name: @yearField.FieldName</li>
</ul>

@code {
    private FieldIdentifier yearField;

    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }

    [Parameter]
    public Expression<Func<int>> YearExpression { get; set; } = default!;

    protected override void OnInitialized()
    {
        yearField = FieldIdentifier.Create(YearExpression);
    }
}

Parent3.razor:

@page "/parent-3"

<PageTitle>Parent 3</PageTitle>

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}
@page "/parent-3"

<PageTitle>Parent 3</PageTitle>

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}
@page "/parent-3"

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}
@page "/parent-3"

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}
@page "/parent-3"

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}
@page "/parent-3"

<h1>Parent Example 3</h1>

<p>Parent <code>year</code>: @year</p>

<ChildParameterExpression @bind-Year="year" />

@code {
    private int year = 1979;
}

Ek kaynaklar