Aracılığıyla paylaş


ASP.NET Core Razor bileşeni işleme

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, işlenmek üzere bir bileşeni el ile tetikleme de StateHasChanged dahil olmak üzere ASP.NET Core Blazor uygulamalarında bileşen işleme açıklanmaktadırRazor.

için işleme kuralları ComponentBase

Bileşenler, bir üst bileşen tarafından bileşen hiyerarşisine ilk eklendiklerinde işlenmelidir. Bir bileşenin işlemesi gereken tek zaman budur. Bileşenler diğer zamanlarda kendi mantığına ve kurallarına göre işlenebilir .

Varsayılan olarak, Razor bileşenler temel sınıftan ComponentBase devralır ve bu, aşağıdaki zamanlarda yeniden yeniden çalıştırmayı tetikleme mantığını içerir:

Aşağıdakilerden biri doğruysa, parametre güncelleştirmeleri nedeniyle atla rerender'lerinden ComponentBase devralınan bileşenler:

  • Tüm parametreler bilinen türler kümesinden† veya önceki parametre kümesi ayarlandıktan sonra değişmemiş herhangi bir ilkel türdendir .

    † Framework Blazor , değişiklik algılama için bir dizi yerleşik kural ve açık parametre türü denetimleri kullanır. Bu kurallar ve türler herhangi bir zamanda değiştirilebilir. Daha fazla bilgi için ASP.NET Core başvuru kaynağındaki API'ye bakın.ChangeDetection

    Not

    .NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

  • Bileşenin yöntemini geçersiz kılma işlevi döndürür false (varsayılan ComponentBase uygulama her zaman döndürürtrue).ShouldRender

İşleme akışını denetleme

Çoğu durumda kurallar, ComponentBase bir olay gerçekleştikten sonra bileşen rerender'lerinin doğru alt kümesiyle sonuçlanır. Geliştiricilerin genellikle çerçeveye hangi bileşenlerin yeniden ve ne zaman yeniden çalıştıracaklarını bildirmek için el ile mantık sağlaması gerekmez. Çerçeve kurallarının genel etkisi, bir olay alan bileşenin kendisini yeniden oluşturması ve bu da parametre değerleri değişmiş olabilecek alt bileşenlerin yeniden başlatılmasını yinelemeli olarak tetiklemektedir.

Çerçeve kurallarının performans etkileri ve bir uygulamanın bileşen hiyerarşisini işleme için iyileştirme hakkında daha fazla bilgi için bkz . ASP.NET Temel Blazor performans en iyi yöntemleri.

Akış işleme

Statik sunucu tarafı işleme (statik SSR) ile akış işlemeyi kullanın veya yanıt akışındaki içerik güncelleştirmelerini akışa almak için ön kayıt kullanın ve uzun süre çalışan zaman uyumsuz görevleri tam olarak işlemek üzere gerçekleştiren bileşenler için kullanıcı deneyimini geliştirin.

Örneğin, sayfa yüklendiğinde verileri işlemek için uzun süre çalışan bir veritabanı sorgusu veya web API çağrısı yapan bir bileşen düşünün. Normalde, sunucu tarafı bileşeni işlemenin bir parçası olarak yürütülen zaman uyumsuz görevlerin, işlenen yanıt gönderilmeden önce tamamlanması gerekir ve bu da sayfanın yüklenmesini geciktirebilir. Sayfayı işlemedeki önemli gecikmeler kullanıcı deneyimine zarar veriyor. Kullanıcı deneyimini geliştirmek için akış işleme başlangıçta zaman uyumsuz işlemler yürütülürken tüm sayfayı yer tutucu içerikle hızlı bir şekilde işler. İşlemler tamamlandıktan sonra, güncelleştirilmiş içerik aynı yanıt bağlantısında istemciye gönderilir ve DOM'a düzeltme eki eklenir.

Akış işleme, sunucunun çıkışı arabelleğe almaktan kaçınmasını gerektirir. Veriler oluşturulurken yanıt verilerinin istemciye akması gerekir. Arabelleğe almayı zorunlu kılan konaklar için akış işleme düzgün bir şekilde düşer ve akış işleme olmadan sayfa yüklenir.

Statik sunucu tarafı işleme (statik SSR) veya ön kayıt kullanılırken içerik güncelleştirmelerinin akışını yapmak için özniteliğini bileşene uygulayın [StreamRendering(true)] . Akışlı güncelleştirmeler sayfadaki içeriğin değişmesine neden olabileceğinden akış işleme açıkça etkinleştirilmelidir. Özniteliği olmayan bileşenler, üst bileşen özelliği kullanıyorsa akış işlemeyi otomatik olarak benimser. Bu noktada özelliği devre dışı bırakmak ve bileşen alt ağacının daha aşağısına gitmek için bir alt bileşendeki özniteliğine geçin false . özniteliği, bir Razor sınıf kitaplığı tarafından sağlanan bileşenlere uygulandığında işlevseldir.

Aşağıdaki örnek, Web Uygulaması proje şablonundan oluşturulan bir uygulamadakiBlazorbileşeni temel alırWeather. Çağrısı, Task.Delay hava durumu verilerinin zaman uyumsuz olarak alınmasını simüle eder. Bileşen başlangıçta zaman uyumsuz gecikmenin tamamlanmasını beklemeden yer tutucu içeriği ("Loading...") işler. Zaman uyumsuz gecikme tamamlandığında ve hava durumu verileri içeriği oluşturulduğunda, içerik yanıta akışla aktarılır ve hava durumu tahmin tablosuna düzeltme eki uygulanır.

Weather.razor:

@page "/weather"
@attribute [StreamRendering(true)]

...

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        ...
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    ...

    private WeatherForecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(500);

        ...

        forecasts = ...
    }
}

Kullanıcı arabirimi yenilemesini gizleme (ShouldRender)

ShouldRender bir bileşen her işlendiğinde çağrılır. Kullanıcı arabirimi yenilemeyi yönetmek için geçersiz kılın ShouldRender . Uygulama döndürürse true, kullanıcı arabirimi yenilenir.

Geçersiz kılınmış olsa ShouldRender bile, bileşen her zaman başlangıçta işlenir.

ControlRender.razor:

@page "/control-render"

<PageTitle>Control Render</PageTitle>

<h1>Control Render Example</h1>

<label>
    <input type="checkbox" @bind="shouldRender" />
    Should Render?
</label>

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

<p>
    <button @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;
    private bool shouldRender = true;

    protected override bool ShouldRender()
    {
        return shouldRender;
    }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/control-render"

<label>
    <input type="checkbox" @bind="shouldRender" />
    Should Render?
</label>

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

<p>
    <button @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;
    private bool shouldRender = true;

    protected override bool ShouldRender()
    {
        return shouldRender;
    }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/control-render"

<label>
    <input type="checkbox" @bind="shouldRender" />
    Should Render?
</label>

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

<p>
    <button @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;
    private bool shouldRender = true;

    protected override bool ShouldRender()
    {
        return shouldRender;
    }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/control-render"

<label>
    <input type="checkbox" @bind="shouldRender" />
    Should Render?
</label>

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

<p>
    <button @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;
    private bool shouldRender = true;

    protected override bool ShouldRender()
    {
        return shouldRender;
    }

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/control-render"

<label>
    <input type="checkbox" @bind="shouldRender" />
    Should Render?
</label>

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

<p>
    <button @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;
    private bool shouldRender = true;

    protected override bool ShouldRender()
    {
        return shouldRender;
    }

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

ile ilgili performans en iyi yöntemleri hakkında daha fazla bilgi için ShouldRenderbkz . ASP.NET Temel Blazor performans en iyi yöntemleri.

Ne zaman aranacak? StateHasChanged

Çağırma StateHasChanged , istediğiniz zaman bir işlemeyi tetiklemenizi sağlar. Ancak gereksiz işleme maliyetleri getiren yaygın bir hata olan gereksiz çağrıları StateHasChanged dikkate almamaya dikkat edin.

Kodun şu durumlarda çağrılması StateHasChanged gerekmez:

  • Çoğu rutin olay işleyicisi için bir işleme tetiklediğinden ComponentBase , zaman uyumlu veya zaman uyumsuz olarak olayları düzenli olarak işleme.
  • Tipik yaşam döngüsü olayları için bir işleme tetiklendiğinden, veya gibi OnInitializedOnParametersSetAsynctipik yaşam döngüsü mantığının zaman uyumlu veya zaman uyumsuz olarak ComponentBase uygulanması.

Ancak, bu makalenin aşağıdaki bölümlerinde açıklanan durumlarda çağrı StateHasChanged yapmak mantıklı olabilir:

Zaman uyumsuz işleyici birden çok zaman uyumsuz aşama içerir

Görevlerin .NET'te tanımlanma biçimi nedeniyle, bir alıcısı Task ara zaman uyumsuz durumları değil, yalnızca son tamamlanma durumunu gözlemleyebilir. Bu nedenle, ComponentBase yalnızca ilk döndürülürken Task ve Task son tamamlandığında rerendering tetikleyebilir. Çerçeve, bir bileşenin bir ara nokta serisindeki verileri döndürmesi gibi IAsyncEnumerable<T>diğer ara Tasknoktalarda bileşeni yeniden oluşturmayı bilemez. Ara noktalarda yeniden kullanmak istiyorsanız bu noktalardan arayın StateHasChanged .

Yöntem her IncrementCount yürütüldüğünde sayıyı dört kez güncelleştiren aşağıdaki CounterState1 bileşeni göz önünde bulundurun:

  • Otomatik işlemeler, ilk ve son artımlarından currentCountsonra gerçekleşir.
  • Çerçeve, artırılan ara işleme noktalarında currentCount rerender'leri otomatik olarak tetiklemediğinde, el ile işlemeler çağrıları StateHasChanged tarafından tetiklenir.

CounterState1.razor:

@page "/counter-state-1"

<PageTitle>Counter State 1</PageTitle>

<h1>Counter State Example 1</h1>

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

<p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        // Renders here automatically

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        // Renders here automatically
    }
}
@page "/counter-state-1"

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

<p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        // Renders here automatically

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        // Renders here automatically
    }
}
@page "/counter-state-1"

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

<p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        // Renders here automatically

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        // Renders here automatically
    }
}
@page "/counter-state-1"

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

<p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        // Renders here automatically

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        // Renders here automatically
    }
}
@page "/counter-state-1"

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

<p>
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</p>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        // Renders here automatically

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        StateHasChanged();

        await Task.Delay(1000);
        currentCount++;
        // Renders here automatically
    }
}

İşleme ve olay işleme sistemine harici Blazor bir öğeden çağrı alma

ComponentBase yalnızca kendi yaşam döngüsü yöntemlerini ve Blazortetiklenen olayları bilir. ComponentBase kodda gerçekleşebilecek diğer olayları bilmez. Örneğin, özel bir veri deposu tarafından tetiklenen tüm C# olayları için Blazorbilinmemektedir. Bu tür olayların kullanıcı arabiriminde güncelleştirilmiş değerleri görüntülemek üzere yeniden kayıt işlemini tetiklemesi için öğesini çağırın StateHasChanged.

Bir sayıyı düzenli aralıklarla güncelleştirmek için kullanan System.Timers.Timer ve kullanıcı arabirimini güncelleştirmek için çağıran StateHasChanged aşağıdaki CounterState2 bileşeni göz önünde bulundurun:

  • OnTimerCallback herhangi bir Blazoryönetilen işleme akışının veya olay bildiriminin dışında çalışır. Bu nedenle, OnTimerCallback geri çağırmada yapılan değişikliklerin currentCount farkında olmadığından çağrısı StateHasChangedBlazor yapmalıdır.
  • Bileşen, çerçeve yöntemini çağırdığında Dispose atıldığı öğesini uygular.IDisposableTimer Daha fazla bilgi için bkz. ASP.NET Core Razor bileşeni yaşam döngüsü.

Geri çağırma' eşitleme bağlamının Blazordışında çağrıldığından, bileşenin işleyicinin OnTimerCallback eşitleme bağlamı üzerine taşımak için içindeki ComponentBase.InvokeAsync mantığını sarmalamaları gerekir. Bu, diğer ui çerçevelerinde kullanıcı arabirimi iş parçacığına yönelik sıralamaya eşdeğerdir. StateHasChanged yalnızca işleyicinin eşitleme bağlamından çağrılabilir ve aksi takdirde bir özel durum oluşturur:

System.InvalidOperationException: 'Geçerli iş parçacığı Dispatcher ile ilişkili değil. İşleme veya bileşen durumunu tetiklerken yürütmeyi Dispatcher'a geçmek için InvokeAsync() kullanın.'

CounterState2.razor:

@page "/counter-state-2"
@using System.Timers
@implements IDisposable

<PageTitle>Counter State 2</PageTitle>

<h1>Counter State Example 2</h1>

<p>
    This counter demonstrates <code>Timer</code> disposal.
</p>

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

@code {
    private int currentCount = 0;
    private Timer timer = new(1000);

    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }

    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable

<h1>Counter with <code>Timer</code> disposal</h1>

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

@code {
    private int currentCount = 0;
    private Timer timer = new(1000);

    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }

    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable

<h1>Counter with <code>Timer</code> disposal</h1>

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

@code {
    private int currentCount = 0;
    private Timer timer = new(1000);

    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }

    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable

<h1>Counter with <code>Timer</code> disposal</h1>

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

@code {
    private int currentCount = 0;
    private Timer timer = new(1000);

    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }

    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose() => timer.Dispose();
}
@page "/counter-state-2"
@using System.Timers
@implements IDisposable

<h1>Counter with <code>Timer</code> disposal</h1>

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

@code {
    private int currentCount = 0;
    private Timer timer = new Timer(1000);

    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }

    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose() => timer.Dispose();
}

Belirli bir olay tarafından yeniden kaydedilen alt ağaç dışındaki bir bileşeni işlemek için

Kullanıcı arabirimi şunları içerebilir:

  1. Bir olayı tek bir bileşene dağıtma.
  2. Bazı durum değiştiriliyor.
  3. Olayı alan bileşenin alt öğelerinden biri olmayan tamamen farklı bir bileşeni yeniden oluşturma.

Bu senaryoyla başa çıkmanın bir yolu, genellikle birden çok bileşene eklenen bir bağımlılık ekleme (DI) hizmeti olarak bir durum yönetimi sınıfı sağlamaktır. Bir bileşen durum yöneticisinde bir yöntem çağırdığında, durum yöneticisi bağımsız bir bileşen tarafından alınan bir C# olayı oluşturur.

Durumu yönetme yaklaşımları için aşağıdaki kaynaklara bakın:

Durum yöneticisi yaklaşımı için C# olayları işleme işlem hattının Blazor dışındadır. Durum yöneticisinin olaylarına yanıt olarak yeniden kullanmak istediğiniz diğer bileşenleri arayın StateHasChanged .

Durum yöneticisi yaklaşımı önceki bölümdeki ile System.Timers.Timerbenzerdir. Yürütme çağrı yığını genellikle işleyicinin eşitleme bağlamında kaldığından, çağrı InvokeAsync normalde gerekli değildir. Çağrısı InvokeAsync yalnızca mantık eşitleme bağlamından kaçarsa (örneğin, üzerinde Task veya ContinueWith ile ConfigureAwait(false)öğesini Task beklerken) gereklidir. Daha fazla bilgi için, İşleme ve olay işleme sistemi dışında Blazor bir öğeden çağrı alma bölümüne bakın.

Web Apps için Blazor WebAssembly yükleme ilerleme durumu göstergesi

Web Uygulaması proje şablonundan Blazor oluşturulan bir uygulamada yükleme ilerleme durumu göstergesi yoktur. .NET'in gelecekteki bir sürümü için yeni bir yükleme ilerleme durumu göstergesi özelliği planlanıyor. Bu arada, bir uygulama bir yükleme ilerleme durumu göstergesi oluşturmak için özel kod benimseyebilir. Daha fazla bilgi için bkz . ASP.NET Core Blazor başlatma.