Share via


ASP.NET Çekirdek Blazor basamaklı değerleri ve parametreleri

Not

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

Önemli

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

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

Bu makalede, bir ata Razor bileşeninden alt bileşenlere veri akışı açıklanmaktadır.

Basamaklı değerler ve parametreler , bir alt bileşen bileşeninden herhangi bir sayıda alt bileşene veri akışı yapmak için uygun bir yol sağlar. Bileşen parametrelerinden farklı olarak, basamaklı değerler ve parametreler, verilerin kullanıldığı her alt bileşen için bir öznitelik ataması gerektirmez. Basamaklı değerler ve parametreler, bileşenlerin bir bileşen hiyerarşisinde birbirleriyle eşgüdüm sağlamasına da olanak sağlar.

Not

Bu makaledeki kod örnekleri, .NET 6 veya sonraki sürümlerindeki ASP.NET Core'da desteklenen null atanabilir başvuru türlerini (NTS) ve .NET derleyici null durum statik analizini benimser. ASP.NET Core 5.0 veya önceki sürümleri hedeflerken, makalenin örneklerindeki , , , ITab?ve türlerinden CascadingType?null tür atamasını (?) kaldırın.string?TabSet?RenderFragment?@ActiveTab?

Kök düzeyinde basamaklı değerler

Kök düzeyinde basamaklı değerler tüm bileşen hiyerarşisi için kaydedilebilir. Güncelleştirme bildirimleri için adlandırılmış basamaklı değerler ve abonelikler desteklenir.

Bu bölümün örneklerinde aşağıdaki sınıf kullanılmıştır.

Dalek.cs:

// "Dalek" ©Terry Nation https://www.imdb.com/name/nm0622334/
// "Doctor Who" ©BBC https://www.bbc.co.uk/programmes/b006q2x0

namespace BlazorSample;

public class Dalek
{
    public int Units { get; set; }
}

Aşağıdaki kayıtlar ile uygulamanın Program dosyasında AddCascadingValueyapılır:

  • Dalek için bir özellik değeri Units ile sabit basamaklı değer olarak kaydedilir.
  • için Units farklı bir özellik değerine sahip ikinci Dalek kayıt "AlphaGroup" olarak adlandırılır.
builder.Services.AddCascadingValue(sp => new Dalek { Units = 123 });
builder.Services.AddCascadingValue("AlphaGroup", sp => new Dalek { Units = 456 });

Aşağıdaki Daleks bileşen basamaklı değerleri görüntüler.

Daleks.razor:

@page "/daleks"

<PageTitle>Daleks</PageTitle>

<h1>Root-level Cascading Value Example</h1>

<ul>
    <li>Dalek Units: @Dalek?.Units</li>
    <li>Alpha Group Dalek Units: @AlphaGroupDalek?.Units</li>
</ul>

<p>
    Dalek© <a href="https://www.imdb.com/name/nm0622334/">Terry Nation</a><br>
    Doctor Who© <a href="https://www.bbc.co.uk/programmes/b006q2x0">BBC</a>
</p>

@code {
    [CascadingParameter]
    public Dalek? Dalek { get; set; }

    [CascadingParameter(Name = "AlphaGroup")]
    public Dalek? AlphaGroupDalek { get; set; }
}

Aşağıdaki örnekte, Dalek kullanılarak CascadingValueSource<T>basamaklı bir değer olarak kaydedilir; burada <T> türüdür. bayrağı değerin isFixed sabit olup olmadığını gösterir. False ise, tüm alıcılar çağrılarak NotifyChangedAsyncverilen güncelleştirme bildirimlerine abone olur. Abonelikler ek yük oluşturur ve performansı azaltır, dolayısıyla değer değişmezse olarak ayarlanır isFixedtrue .

builder.Services.AddCascadingValue(sp =>
{
    var dalek = new Dalek { Units = 789 };
    var source = new CascadingValueSource<Dalek>(dalek, isFixed: false);
    return source;
});

Uyarı

Bir bileşen türünün kök düzeyinde basamaklı değer olarak kaydedilmesi, tür için ek hizmetler kaydetmez veya bileşende hizmet etkinleştirmesine izin vermez.

Gerekli hizmetleri basamaklı değerlerden ayrı olarak değerlendirin ve bunları basamaklı türden ayrı olarak kaydedin.

Bir bileşen türünü basamaklı değer olarak kaydetmek için kullanmaktan AddCascadingValue kaçının. Bunun yerine bileşenini (Components/Routes.razor) bileşeniyle sarmalayıp <Router>...</Router>Routes genel etkileşimli sunucu tarafı işlemeyi (etkileşimli SSR) benimseyin. Bir örnek için bileşen bölümüne bakınCascadingValue.

CascadingValue bileşeni

Bir üst bileşen, bir bileşen hiyerarşisinin Blazor alt ağacını sarmalayan ve alt ağacı içindeki tüm bileşenlere tek bir değer sağlayan çerçevenin CascadingValue bileşenini kullanarak basamaklı bir değer sağlar.

Aşağıdaki örnek, alt bileşenlerdeki düğmelere CSS stil sınıfı sağlamak için bileşen hiyerarşisinde tema bilgilerinin akışını gösterir.

Aşağıdaki ThemeInfo C# sınıfı tema bilgilerini belirtir.

Not

Bu bölümdeki örnekler için uygulamanın ad alanı şeklindedir BlazorSample. Kendi örnek uygulamanızdaki kodla denemeler yaparken, uygulamanın ad alanını örnek uygulamanızın ad alanıyla değiştirin.

ThemeInfo.cs:

namespace BlazorSample;

public class ThemeInfo
{
    public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses;

public class ThemeInfo
{
    public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses;

public class ThemeInfo
{
    public string? ButtonClass { get; set; }
}
namespace BlazorSample.UIThemeClasses
{
    public class ThemeInfo
    {
        public string ButtonClass { get; set; }
    }
}
namespace BlazorSample.UIThemeClasses
{
    public class ThemeInfo
    {
        public string ButtonClass { get; set; }
    }
}

Aşağıdaki düzen bileşeni , tema bilgilerini (ThemeInfo) özelliğin düzen gövdesini Body oluşturan tüm bileşenler için basamaklı değer olarak belirtir. ButtonClass bir Bootstrap düğme stili olan değeri btn-successatanır. Bileşen hiyerarşisindeki herhangi bir alt bileşen, basamaklı değer aracılığıyla ThemeInfo özelliğini kullanabilirButtonClass.

MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
        </div>

        <CascadingValue Value="@theme">
            <article class="content px-4">
                @Body
            </article>
        </CascadingValue>
    </main>
</div>

<div id="blazor-error-ui" data-nosnippet>
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <CascadingValue Value="@theme">
            <article class="content px-4">
                @Body
            </article>
        </CascadingValue>
    </main>
</div>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <CascadingValue Value="@theme">
            <div class="content px-4">
                @Body
            </div>
        </CascadingValue>
    </main>
</div>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <CascadingValue Value="@theme">
            <div class="content px-4">
                @Body
            </div>
        </CascadingValue>
    </div>
</div>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };
}
@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <CascadingValue Value="theme">
        <div class="content px-4">
            @Body
        </div>
    </CascadingValue>
</div>

@code {
    private ThemeInfo theme = new ThemeInfo { ButtonClass = "btn-success" };
}

Blazor Web Apps, uygulamaya tek bir düzen dosyası aracılığıyla sağlamaktan daha geniş kapsamlı olarak geçerli olan basamaklı değerler için alternatif yaklaşımlar sağlar:

  • Verileri uygulamanın tüm bileşenleri için basamaklı değer olarak belirtmek üzere bileşenin işaretlemesini Routes bir CascadingValue bileşene sarmalar.

    Aşağıdaki örnek, bileşenden Routes verileri basamaklarThemeInfo.

    Routes.razor:

    <CascadingValue Value="theme">
        <Router ...>
            ...
        </Router>
    </CascadingValue>
    
    @code {
        private ThemeInfo theme = new() { ButtonClass = "btn-success" };
    }
    

    Not

    Bileşendeki Routes (Components/App.razor) bileşen örneğini App bir CascadingValue bileşenle sarmalama desteklenmez.

  • Hizmet koleksiyonu oluşturucusunun uzantı yöntemini çağırarak AddCascadingValue hizmet olarak kök düzeyinde basamaklı bir değer belirtin.

    Aşağıdaki örnek, dosyadaki Program verileri basamaklarThemeInfo.

    Program.cs

    builder.Services.AddCascadingValue(sp => 
        new ThemeInfo() { ButtonClass = "btn-primary" });
    

Daha fazla bilgi için bu makalenin aşağıdaki bölümlerine bakın:

[CascadingParameter] özniteliği

Basamaklı değerleri kullanmak için, alt bileşenler özniteliğini [CascadingParameter]kullanarak basamaklı parametreler bildirir. Basamaklı değerler türe göre basamaklı parametrelere bağlıdır. Aynı türdeki birden çok değeri basamaklama, bu makalenin devamında yer alan Birden çok değeri basamaklama bölümünde ele alınmıştır.

Aşağıdaki bileşen, basamaklı değeri isteğe bağlı olarak aynı adı ThemeInfokullanarak basamaklı bir parametreye bağlarThemeInfo. parametresi, düğmenin CSS sınıfını Increment Counter (Themed) ayarlamak için kullanılır.

ThemedCounter.razor:

@page "/themed-counter"

<PageTitle>Themed Counter</PageTitle>

<h1>Themed Counter Example</h1>

<p>Current count: @currentCount</p>

<p>
    <button @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button 
        class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)" 
        @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo? ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses

<h1>Themed Counter</h1>

<p>Current count: @currentCount</p>

<p>
    <button @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button 
        class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)" 
        @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo? ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses

<h1>Themed Counter</h1>

<p>Current count: @currentCount</p>

<p>
    <button @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button 
        class="btn @(ThemeInfo is not null ? ThemeInfo.ButtonClass : string.Empty)" 
        @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo? ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses

<h1>Themed Counter</h1>

<p>Current count: @currentCount</p>

<p>
    <button @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/themed-counter"
@using BlazorSample.UIThemeClasses

<h1>Themed Counter</h1>

<p>Current count: @currentCount</p>

<p>
    <button @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo ThemeInfo { get; set; }

    private void IncrementCount()
    {
        currentCount++;
    }
}

Normal bileşen parametresine benzer şekilde, basamaklı bir parametreyi kabul eden bileşenler, basamaklı değer değiştirildiğinde yeniden oluşturulur. Örneğin, farklı bir tema örneğinin yapılandırılması bileşenin ThemedCounter bileşen bölümünden CascadingValue yeniden yapılandırılmasına neden olur.

MainLayout.razor:

<main>
    <div class="top-row px-4">
        <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
    </div>

    <CascadingValue Value="theme">
        <article class="content px-4">
            @Body
        </article>
    </CascadingValue>
    <button @onclick="ChangeToDarkTheme">Dark mode</button>
</main>

@code {
    private ThemeInfo theme = new() { ButtonClass = "btn-success" };

    private void ChangeToDarkTheme()
    {
        theme = new() { ButtonClass = "btn-secondary" };
    }
}

CascadingValue<TValue>.IsFixed , basamaklı parametrenin başlatmadan sonra değişmediğini belirtmek için kullanılabilir.

Basamaklı değerler/parametreler ve işleme modu sınırları

Basamaklı parametreler işleme modu sınırları arasında veri geçirmez:

  • Etkileşimli oturumlar, statik sunucu tarafı işleme (statik SSR) kullanan sayfalardan farklı bir bağlamda çalışır. Sayfayı üreten sunucunun, sunucunun istemciden farklı bir makine olduğu WebAssembly bileşenleri de dahil olmak üzere daha sonraki Etkileşimli Sunucu oturumlarını barındıran makineyle aynı olması gerekmez. Statik sunucu tarafı işlemenin (statik SSR) avantajı, durum bilgisi olmayan html işlemenin tam performansını elde etmektir.

  • Statik ve etkileşimli işleme arasındaki sınırı geçen durum serileştirilebilir olmalıdır. Bileşenler işleyici, DI kapsayıcısı ve her DI hizmeti örneği dahil olmak üzere diğer nesnelerin geniş bir zincirine başvuran rastgele nesnelerdir. Durumu etkileşimli olarak işlenen sonraki bileşenlerde kullanılabilir hale getirmek için statik SSR'den seri hale getirilmesine açıkça neden olmanız gerekir. İki yaklaşım benimsenmiştir:

    • Blazor Çerçeve aracılığıyla, statik bir SSR üzerinden etkileşimli işleme sınırına geçirilen parametreler ON-serializable ise veya bir hata oluşursa JSotomatik olarak serileştirilir.
    • on-serializable PersistentComponentState ise veya bir hata oluşursa JSiçinde depolanan durum otomatik olarak serileştirilir ve kurtarılır.

Basamaklı parametreler için tipik kullanım desenleri biraz DI hizmetlerine benzer olduğundan, basamaklı parametreler ON serileştirilebilir değildir JS. Genellikle basamaklı parametrelerin platforma özgü çeşitleri vardır, bu nedenle çerçeve geliştiricilerin sunucuya etkileşimli özel sürümlere veya WebAssembly'ye özgü sürümlere sahip olmasını durdurursa geliştiricilere yardımcı olmaz. Ayrıca, genel olarak birçok basamaklı parametre değeri serileştirilebilir değildir, bu nedenle tüm sıralı hale getirilemez basamaklı parametre değerlerini kullanmayı bırakmanız gerekiyorsa mevcut uygulamaları güncelleştirmek pratik olmaz.

Öneriler:

  • Durumu basamaklı parametre olarak tüm etkileşimli bileşenler için kullanılabilir hale getirmeniz gerekiyorsa, kök düzeyinde basamaklı değerler kullanmanızı öneririz. Bir fabrika düzeni kullanılabilir ve uygulama, uygulama başlangıcından sonra güncelleştirilmiş değerler yayabilir. Di hizmetleri olarak işlendiği için, kök düzeyinde basamaklı değerler etkileşimli bileşenler de dahil olmak üzere tüm bileşenler tarafından kullanılabilir.

  • Bileşen kitaplığı yazarları için, kitaplık tüketicileri için aşağıdakine benzer bir uzantı yöntemi oluşturabilirsiniz:

    builder.Services.AddLibraryCascadingParameters();
    

    Geliştiricilere uzantı yönteminizi çağırmalarını sağlayın. Bu, bileşenlerine bir bileşen eklemelerini MainLayout bildirmek için bir <RootComponent> ses alternatifidir.

Birden çok değeri art arda basamaklama

Aynı alt ağaç içinde aynı türdeki birden çok değeri art arda eklemek için, her CascadingValue bileşene ve ilgili [CascadingParameter] özniteliklerine benzersiz Name bir dize sağlayın.

Aşağıdaki örnekte, iki CascadingValue bileşen farklı örneklerini art arda sıralar CascadingType:

<CascadingValue Value="parentCascadeParameter1" Name="CascadeParam1">
    <CascadingValue Value="ParentCascadeParameter2" Name="CascadeParam2">
        ...
    </CascadingValue>
</CascadingValue>

@code {
    private CascadingType? parentCascadeParameter1;

    [Parameter]
    public CascadingType? ParentCascadeParameter2 { get; set; }
}

Alt bileşende basamaklı parametreler, basamaklı değerlerini ile ata bileşeninden Namealır:

@code {
    [CascadingParameter(Name = "CascadeParam1")]
    protected CascadingType? ChildCascadeParameter1 { get; set; }

    [CascadingParameter(Name = "CascadeParam2")]
    protected CascadingType? ChildCascadeParameter2 { get; set; }
}

Bileşen hiyerarşisi boyunca verileri geçirme

Basamaklı parametreler, bileşenlerin bir bileşen hiyerarşisinde veri geçirmesini de sağlar. Bir sekme kümesi bileşeninin bir dizi ayrı sekmeyi barındırdığı aşağıdaki kullanıcı arabirimi sekmesi kümesi örneğini göz önünde bulundurun.

Not

Bu bölümdeki örnekler için uygulamanın ad alanı şeklindedir BlazorSample. Kendi örnek uygulamanızdaki kodla denemeler yaparken, ad alanını örnek uygulamanızın ad alanı olarak değiştirin.

Sekmelerin adlı UIInterfacesbir ITab klasörde uyguladığı bir arabirim oluşturun.

UIInterfaces/ITab.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.UIInterfaces;

public interface ITab
{
    RenderFragment ChildContent { get; }
}

Not

hakkında RenderFragmentdaha fazla bilgi için bkz . ASP.NET Core Razor bileşenleri.

Aşağıdaki TabSet bileşen bir sekme kümesi tutar. Bu bölümün ilerleyen bölümlerinde oluşturulan sekme kümesinin Tab bileşenleri, liste () için liste öğelerini (<li>...</li><ul>...</ul>) sağlayın.

Alt Tab bileşenler açıkça parametresi olarak geçirilmemektedir TabSet. Bunun yerine, alt Tab bileşenler öğesinin alt içeriğinin TabSetbir parçasıdır. Ancak, TabSet yine de üst bilgileri ve etkin sekmeyi işleyebilmesi için her Tab bileşene bir başvuru gerekir. Ek kod gerektirmeden bu koordinasyonu TabSet etkinleştirmek için, bileşen kendisini alt bileşenler tarafından Tab seçilen basamaklı bir değer olarak sağlayabilir.

TabSet.razor:

@using BlazorSample.UIInterfaces

<!-- Display the tab headers -->

<CascadingValue Value="this">
    <ul class="nav nav-tabs">
        @ChildContent
    </ul>
</CascadingValue>

<!-- Display body for only the active tab -->

<div class="nav-tabs-body p-4">
    @ActiveTab?.ChildContent
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public ITab? ActiveTab { get; private set; }

    public void AddTab(ITab tab)
    {
        if (ActiveTab is null)
        {
            SetActiveTab(tab);
        }
    }

    public void SetActiveTab(ITab tab)
    {
        if (ActiveTab != tab)
        {
            ActiveTab = tab;
            StateHasChanged();
        }
    }
}

Tab Alt bileşenler, içeren TabSet öğesini basamaklı parametre olarak yakalar. Tab Bileşenler, etkin sekmeyi TabSet ayarlamak için ve koordinatlarına kendilerini ekler.

Tab.razor:

@using BlazorSample.UIInterfaces
@implements ITab

<li>
    <a @onclick="ActivateTab" class="nav-link @TitleCssClass" role="button">
        @Title
    </a>
</li>

@code {
    [CascadingParameter]
    public TabSet? ContainerTabSet { get; set; }

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

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    private string? TitleCssClass => 
        ContainerTabSet?.ActiveTab == this ? "active" : null;

    protected override void OnInitialized()
    {
        ContainerTabSet?.AddTab(this);
    }

    private void ActivateTab()
    {
        ContainerTabSet?.SetActiveTab(this);
    }
}

Aşağıdaki ExampleTabSet bileşen, üç Tab bileşen içeren bileşeni kullanırTabSet.

ExampleTabSet.razor:

@page "/example-tab-set"

<TabSet>
    <Tab Title="First tab">
        <h4>Greetings from the first tab!</h4>

        <label>
            <input type="checkbox" @bind="showThirdTab" />
            Toggle third tab
        </label>
    </Tab>

    <Tab Title="Second tab">
        <h4>Hello from the second tab!</h4>
    </Tab>

    @if (showThirdTab)
    {
        <Tab Title="Third tab">
            <h4>Welcome to the disappearing third tab!</h4>
            <p>Toggle this tab from the first tab.</p>
        </Tab>
    }
</TabSet>

@code {
    private bool showThirdTab;
}

Ek kaynaklar