Aracılığıyla paylaş


ASP.NET Core Razor bileşeni sanallaştırma

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.

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 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, ASP.NET Core Blazor uygulamalarında bileşen sanallaştırmanın nasıl kullanılacağı açıklanmaktadır.

Sanallaştırma

Çerçevenin bileşenle birlikte yerleşik sanallaştırma desteğini kullanarak Blazor bileşen işlemenin algılanan performansını geliştirin Virtualize<TItem> . Sanallaştırma, kullanıcı arabirimi işlemeyi yalnızca görünür olan bölümle sınırlamak için kullanılan bir tekniktir. Örneğin, uygulamanın uzun bir öğe listesini işlemesi gerektiğinde ve herhangi bir zamanda yalnızca bir öğe alt kümesinin görünür olması gerektiğinde sanallaştırma yararlı olur.

Bileşeni şu Virtualize<TItem> durumlarda kullanın:

  • Bir döngüdeki veri öğeleri kümesini işleme.
  • Kaydırma nedeniyle öğelerin çoğu görünmüyor.
  • İşlenen öğeler aynı boyuttadır.

Kullanıcı, bileşenin öğe listesinde rastgele bir noktaya Virtualize<TItem> kaydırdığında, bileşen gösterilecek görünür öğeleri hesaplar. Görünmeyen öğeler işlenmez.

Sanallaştırma olmadan, tipik bir liste bir listedeki her öğeyi işlemek için bir C# foreach döngüsü kullanabilir. Aşağıdaki örnekte:

  • allFlights uçak uçuşlarından oluşan bir koleksiyondur.
  • Bileşen her FlightSummary uçuşla ilgili ayrıntıları görüntüler.
  • @key yönerge özniteliği, her FlightSummary bileşenin, tarafından FlightIdişlenen uçuşu ile olan ilişkisini korur.
<div style="height:500px;overflow-y:scroll">
    @foreach (var flight in allFlights)
    {
        <FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
    }
</div>

Koleksiyon binlerce uçuş içeriyorsa, uçuşların işlenmesi uzun sürer ve kullanıcılar fark edilebilir bir kullanıcı arabirimi gecikmesi yaşar. Uçuşların çoğu öğenin yüksekliğinin <div> dışındadır, bu nedenle çoğu görülmez.

Uçuş listesinin tamamını aynı anda işlemek yerine, önceki örnekteki döngüsünü bileşeniyle Virtualize<TItem> değiştirinforeach:

  • için sabit öğe kaynağı Virtualize<TItem>.Itemsolarak belirtinallFlights. Yalnızca şu anda görünür olan uçuşlar bileşen tarafından Virtualize<TItem> işlenir.

    Genel olmayan bir koleksiyon öğeleri (örneğin, bir koleksiyonu) DataRowsağlarsa, öğeleri sağlamak için Öğe sağlayıcısı temsilcisi bölümündeki yönergeleri izleyin.

  • Parametresiyle Context her bir uçuş için bir bağlam belirtin. Aşağıdaki örnekte, flight her bir uçuşun üyelerine erişim sağlayan bağlam olarak kullanılır.

<div style="height:500px;overflow-y:scroll">
    <Virtualize Items="allFlights" Context="flight">
        <FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
    </Virtualize>
</div>

parametresiyle Context bir bağlam belirtilmezse, her bir uçuşun üyelerine erişmek için öğe içerik şablonundaki değerini context kullanın:

<div style="height:500px;overflow-y:scroll">
    <Virtualize Items="allFlights">
        <FlightSummary @key="context.FlightId" Details="@context.Summary" />
    </Virtualize>
</div>

Bileşen Virtualize<TItem> :

  • Kapsayıcının yüksekliğine ve işlenen öğelerin boyutuna göre işlenmek üzere öğe sayısını hesaplar.
  • Kullanıcı kaydırdıkça öğeleri yeniden hesaplar ve yeniden hesaplar.
  • Kayıtların dilimini yalnızca yerine kullanılan ItemsProvider Items overscan da dahil olmak üzere görünür durumdaki bölgeye karşılık gelen bir dış API'den getirir (bkz . Öğe sağlayıcısı temsilcisi bölümü).

Bileşenin öğe içeriği şunları Virtualize<TItem> içerebilir:

  • Önceki örnekte gösterildiği gibi Düz HTML ve Razor kod.
  • Bir veya daha fazla Razor bileşen.
  • HTML/Razor ve Razor bileşenlerin karışımı.

Öğe sağlayıcısı temsilcisi

Tüm öğeleri belleğe yüklemek istemiyorsanız veya koleksiyon genel ICollection<T>değilse, istenen öğeleri isteğe bağlı olarak zaman uyumsuz olarak alan bileşenin Virtualize<TItem>.ItemsProvider parametresine bir öğe sağlayıcısı temsilci yöntemi belirtebilirsiniz. Aşağıdaki örnekte yöntemi, LoadEmployees bileşene Virtualize<TItem> öğeleri sağlar:

<Virtualize Context="employee" ItemsProvider="LoadEmployees">
    <p>
        @employee.FirstName @employee.LastName has the 
        job title of @employee.JobTitle.
    </p>
</Virtualize>

Öğe sağlayıcısı, belirli bir ItemsProviderRequestbaşlangıç dizininden başlayan gerekli öğe sayısını belirten bir alır. Ardından öğe sağlayıcısı istenen öğeleri bir veritabanından veya başka bir hizmetten alır ve toplam öğe sayısıyla birlikte bir ItemsProviderResult<TItem> olarak döndürür. Öğe sağlayıcısı, her istekle birlikte öğeleri almayı veya bunları önbelleğe alıp hazır olmalarını sağlayabilir.

Bileşen Virtualize<TItem> parametrelerinden yalnızca bir öğe kaynağını kabul edebilir, bu nedenle bir öğe sağlayıcısını aynı anda kullanmayı denemeyin ve öğesine bir koleksiyon atayınItems. Her ikisi de atanmışsa, bileşenin parametreleri çalışma zamanında ayarlandığında bir InvalidOperationException oluşturulur.

Aşağıdaki örnek, bir 'den EmployeeService çalışanları yükler (gösterilmez):

private async ValueTask<ItemsProviderResult<Employee>> LoadEmployees(
    ItemsProviderRequest request)
{
    var numEmployees = Math.Min(request.Count, totalEmployees - request.StartIndex);
    var employees = await EmployeesService.GetEmployeesAsync(request.StartIndex, 
        numEmployees, request.CancellationToken);

    return new ItemsProviderResult<Employee>(employees, totalEmployees);
}

Aşağıdaki örnekte koleksiyonu genel olmayan bir koleksiyon DataRow olduğundan, öğe sağlayıcısı temsilcisi sanallaştırma için kullanılır:

<Virtualize Context="row" ItemsProvider="GetRows">
    ...
</Virtualize>

@code{
    ...

    private ValueTask<ItemsProviderResult<DataRow>> GetRows(ItemsProviderRequest request) => 
        new(new ItemsProviderResult<DataRow>(
            dataTable.Rows.OfType<DataRow>().Skip(request.StartIndex).Take(request.Count),
            dataTable.Rows.Count));
}

Virtualize<TItem>.RefreshDataAsync bileşenine içindeki verileri yeniden sorgulamasını ItemsProvidersağlar. Bu, dış veriler değiştiğinde kullanışlıdır. kullanırken Itemsgenellikle çağrısı RefreshDataAsync yapmanız gerekmez.

RefreshDataAsyncVirtualize<TItem> bir bileşenin verilerini rerender'a neden olmadan güncelleştirir. Bir olay işleyicisinden veya bileşen yaşam döngüsü yönteminden Blazor çağrılırsaRefreshDataAsync, bir işleme olay işleyicisinin veya yaşam döngüsü yönteminin sonunda otomatik olarak tetiklendiğinden işleme tetiklenmesi gerekmez. Aşağıdaki ForecastUpdated temsilci gibi bir arka plan görevinden veya olayından ayrı olarak tetikleniyorsaRefreshDataAsync, arka plan görevinin veya olayının sonunda kullanıcı arabirimini güncelleştirmek için çağrısı StateHasChanged yapın:

<Virtualize ... @ref="virtualizeComponent">
    ...
</Virtualize>

...

private Virtualize<FetchData>? virtualizeComponent;

protected override void OnInitialized()
{
    WeatherForecastSource.ForecastUpdated += async () => 
    {
        await InvokeAsync(async () =>
        {
            await virtualizeComponent?.RefreshDataAsync();
            StateHasChanged();
        });
    });
}

Yukarıdaki örnekte:

  • RefreshDataAsync bileşen için yeni verileri almak için ilk olarak çağrılır Virtualize<TItem> .
  • StateHasChanged bileşeni yeniden kullanmak için çağrılır.

Yer tutucu

Uzak veri kaynağından öğe istemek biraz zaman alabileceğinden, öğe içeriğiyle yer tutucu işleme seçeneğiniz vardır:

  • Öğe verileri kullanılabilir olana kadar içeriği görüntülemek için (Placeholder<Placeholder>...</Placeholder>) kullanın.
  • Listenin öğe şablonunu ayarlamak için kullanın Virtualize<TItem>.ItemContent .
<Virtualize Context="employee" ItemsProvider="LoadEmployees">
    <ItemContent>
        <p>
            @employee.FirstName @employee.LastName has the 
            job title of @employee.JobTitle.
        </p>
    </ItemContent>
    <Placeholder>
        <p>
            Loading&hellip;
        </p>
    </Placeholder>
</Virtualize>

boş içerik

EmptyContent Bileşen yüklendiğinde ve Items boş olduğunda veya ItemsProviderResult<TItem>.TotalItemCount sıfır olduğunda içerik sağlamak için parametresini kullanın.

EmptyContent.razor:

@page "/empty-content"

<PageTitle>Empty Content</PageTitle>

<h1>Empty Content Example</h1>

<Virtualize Items="stringList">
    <ItemContent>
        <p>
            @context
        </p>
    </ItemContent>
    <EmptyContent>
        <p>
            There are no strings to display.
        </p>
    </EmptyContent>
</Virtualize>

@code {
    private List<string>? stringList;

    protected override void OnInitialized() => stringList ??= new();
}
@page "/empty-content"

<PageTitle>Empty Content</PageTitle>

<h1>Empty Content Example</h1>

<Virtualize Items="stringList">
    <ItemContent>
        <p>
            @context
        </p>
    </ItemContent>
    <EmptyContent>
        <p>
            There are no strings to display.
        </p>
    </EmptyContent>
</Virtualize>

@code {
    private List<string>? stringList;

    protected override void OnInitialized() => stringList ??= new();
}

OnInitialized Bileşen görüntüleme dizelerini görmek için lambda yöntemini değiştirin:

protected override void OnInitialized() =>
    stringList ??= new() { "Here's a string!", "Here's another string!" };

Öğe boyutu

Her öğenin piksel cinsinden yüksekliği ile Virtualize<TItem>.ItemSize ayarlanabilir (varsayılan: 50). Aşağıdaki örnek, her öğenin yüksekliğini varsayılan 50 pikselden 25 piksele değiştirir:

<Virtualize Context="employee" Items="employees" ItemSize="25">
    ...
</Virtualize>

Bileşen, Virtualize<TItem> ilk işleme gerçekleştikten sonra tek tek öğelerin işleme boyutunu (yüksekliğini) ölçer. Doğru ilk işleme performansına yardımcı olmak ve sayfa yeniden yüklemeleri için doğru kaydırma konumunu sağlamak üzere önceden tam bir öğe boyutu sağlamak için kullanın ItemSize . Varsayılan değer ItemSize bazı öğelerin görünür durumdaki görünümün dışında işlenmesine neden oluyorsa ikinci bir rerender tetiklenmiş olur. Sanallaştırılmış bir listede tarayıcının kaydırma konumunu doğru şekilde korumak için ilk işlemenin doğru olması gerekir. Aksi takdirde, kullanıcılar yanlış öğeleri görüntüleyebilir.

Fazla tarama sayısı

Virtualize<TItem>.OverscanCount görünür bölgeden önce ve sonra kaç ek öğenin işleneceğini belirler. Bu ayar, kaydırma sırasında işleme sıklığını azaltmaya yardımcı olur. Ancak, daha yüksek değerler sayfada daha fazla öğe işlenmesine neden olur (varsayılan: 3). Aşağıdaki örnek, üç öğenin varsayılanı olan overscan sayısını dört öğeye değiştirir:

<Virtualize Context="employee" Items="employees" OverscanCount="4">
    ...
</Virtualize>

Durum değişiklikleri

Bileşen tarafından işlenen öğelerde Virtualize<TItem> değişiklik yaparken, bileşenin yeniden değerlendirilmesini ve yeniden oluşturulmasını sıralamak için çağrısı StateHasChanged yapın. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme.

Klavye kaydırma desteği

Kullanıcıların klavyelerini kullanarak sanallaştırılmış içeriği kaydırmasına izin vermek için, sanallaştırılmış öğelerin veya kaydırma kapsayıcısının odaklanılabilir olduğundan emin olun. Bu adımı atamazsanız, klavye kaydırma Chromium tabanlı tarayıcılarda çalışmaz.

Örneğin, kaydırma kapsayıcısı üzerinde bir tabindex öznitelik kullanabilirsiniz:

<div style="height:500px; overflow-y:scroll" tabindex="-1">
    <Virtualize Items="allFlights">
        <div class="flight-info">...</div>
    </Virtualize>
</div>

, veya diğer değerlerin tabindex -1anlamı hakkında daha fazla bilgi edinmek için bkz tabindex . (MDN belgeleri). 0

Gelişmiş stiller ve kaydırma algılama

Bileşen Virtualize<TItem> yalnızca belirli öğe düzeni mekanizmalarını destekleyecek şekilde tasarlanmıştır. Hangi öğe düzenlerinin doğru çalıştığını anlamak için, aşağıdakiler hangi öğelerin doğru yerde görüntülenmesi gerektiğini nasıl Virtualize algıladığını açıklar.

Kaynak kodunuz aşağıdaki gibi görünüyorsa:

<div style="height:500px; overflow-y:scroll" tabindex="-1">
    <Virtualize Items="allFlights" ItemSize="100">
        <div class="flight-info">Flight @context.Id</div>
    </Virtualize>
</div>

Çalışma zamanında bileşen aşağıdakine Virtualize<TItem> benzer bir DOM yapısı işler:

<div style="height:500px; overflow-y:scroll" tabindex="-1">
    <div style="height:1100px"></div>
    <div class="flight-info">Flight 12</div>
    <div class="flight-info">Flight 13</div>
    <div class="flight-info">Flight 14</div>
    <div class="flight-info">Flight 15</div>
    <div class="flight-info">Flight 16</div>
    <div style="height:3400px"></div>
</div>

İşlenen gerçek satır sayısı ve boşluk oluşturucuların boyutu, stilinize ve Items koleksiyon boyutuna göre değişir. Ancak, içeriğinizden önce ve sonra eklenen aralayıcı div öğeleri olduğuna dikkat edin. Bunlar iki amaca hizmet eder:

  • İçeriğinizden önce ve sonra bir uzaklık sağlamak için, şu anda görünür durumdaki öğelerin kaydırma aralığında doğru konumda görünmesine ve kaydırma aralığının tüm içeriğin toplam boyutunu temsil etmesine neden olur.
  • Kullanıcının geçerli görünür aralığın ötesine ne zaman kaydığını algılamak için, başka bir deyişle farklı içeriğin işlenmesi gerekir.

Not

Aralayıcı HTML öğesi etiketini denetlemeyi öğrenmek için, bu makalenin devamında Yer alan Ara çubuğu öğesi etiketi adını denetleme bölümüne bakın.

Aralayıcı öğeleri, görünür hale geldikleri zaman bildirim almak için dahili olarak bir Kesişim Gözlemcisi kullanır. Virtualize bu olayları almaya bağlıdır.

Virtualize aşağıdaki koşullar altında çalışır:

  • Yer tutucu içerik de dahil olmak üzere işlenen tüm içerik öğeleri aynı yüksekliktedir. Bu, önce her veri öğesini getirmeden ve verileri bir DOM öğesinde işlemeden belirli bir kaydırma konumuna karşılık gelen içeriği hesaplamayı mümkün kılar.

  • Hem aralayıcılar hem de içerik satırları tek bir dikey yığında işlenir ve her öğe tüm yatay genişliği doldurur. Tipik kullanım örneklerinde öğelerle Virtualize div çalışır. DAHA gelişmiş bir düzen oluşturmak için CSS kullanıyorsanız aşağıdaki gereksinimleri göz önünde bulundurun:

    • Kaydırma kapsayıcısı stili için aşağıdaki değerlerden herhangi biriyle bir display gerekir:
      • block (bir diviçin varsayılan).
      • table-row-group (bir tbodyiçin varsayılan).
      • flex olarak flex-direction ayarlanmış olarak columnayarlayın. Bileşenin hemen alt öğelerinin Virtualize<TItem> esnek kurallar altında küçülmediğinden emin olun. Örneğin, .mycontainer > div { flex-shrink: 0 } ekleyin.
    • İçerik satırı stili için aşağıdaki değerlerden biriyle bir display gerekir:
      • block (bir diviçin varsayılan).
      • table-row (bir triçin varsayılan).
    • Boşluk oluşturucu öğelerinin düzenine müdahale etmek için CSS kullanmayın. Aralayıcı öğelerinin blockdeğeri, display üst öğe bir tablo satırı grubu olması dışında olur ve bu durumda varsayılan table-rowolarak olur. Ara öğe genişliğini veya yüksekliğini etkilemeye çalışmayın; bunların kenarlık veya content sahte öğelere sahip olmasına neden olun.

Aralayıcıların ve içerik öğelerinin tek bir dikey yığın olarak işlenmesini durduran veya içerik öğelerinin yüksekliğinin değişmesine neden olan herhangi bir yaklaşım, bileşenin Virtualize<TItem> doğru çalışmasını engeller.

Kök düzeyinde sanallaştırma

Bileşen, Virtualize<TItem> belgenin overflow-y: scrollkendisini ile başka bir öğeye sahip olmanın alternatifi olarak kaydırma kökü olarak kullanmayı destekler. Aşağıdaki örnekte, <html> veya <body> öğeleri ile overflow-y: scrollbir bileşende stillendirilir:

<HeadContent>
    <style>
        html, body { overflow-y: scroll }
    </style>
</HeadContent>

Bileşen, Virtualize<TItem> belgenin overflow-y: scrollkendisini ile başka bir öğeye sahip olmanın alternatifi olarak kaydırma kökü olarak kullanmayı destekler. Belgeyi kaydırma kökü olarak kullanırken, kesişim gözlemcisinin <html> sayfanın tam kaydırılabilir yüksekliğini yalnızca pencere görünüm penceresi yerine görünür bölge olarak görmesine neden olduğundan veya <body> öğelerini ile overflow-y: scroll şekillendirmekten kaçının.

Büyük bir sanallaştırılmış liste oluşturarak (örneğin, 100.000 öğe) ve sayfa CSS stillerinde ile html { overflow-y: scroll } belgeyi kaydırma kökü olarak kullanmayı deneyerek bu sorunu yeniden oluşturabilirsiniz. Bazen düzgün çalışsa da, tarayıcı işlemenin başlangıcında en az bir kez 100.000 öğenin tümünü işlemeyi dener ve bu da tarayıcı sekmesinin kilitlenmesine neden olabilir.

.NET 7'nin yayımlanmasından önce bu soruna geçici bir çözüm bulmak için öğeleri stilden <html>/<body> overflow-y: scroll kaçının veya alternatif bir yaklaşım benimseyin. Aşağıdaki örnekte, öğesinin yüksekliği görünüm penceresi yüksekliğinin <html> %100'ünden biraz fazla olarak ayarlanmıştır:

<HeadContent>
    <style>
        html { min-height: calc(100vh + 0.3px) }
    </style>
</HeadContent>

Bileşen, Virtualize<TItem> belgenin overflow-y: scrollkendisini ile başka bir öğeye sahip olmanın alternatifi olarak kaydırma kökü olarak kullanmayı destekler. Belgeyi kaydırma kökü olarak kullanırken, sayfanın tam kaydırılabilir yüksekliğinin <html> yalnızca pencere görünüm penceresi yerine görünür bölge olarak ele alınmasına neden olduğundan veya <body> öğelerini ile overflow-y: scroll şekillendirmekten kaçının.

Büyük bir sanallaştırılmış liste oluşturarak (örneğin, 100.000 öğe) ve sayfa CSS stillerinde ile html { overflow-y: scroll } belgeyi kaydırma kökü olarak kullanmayı deneyerek bu sorunu yeniden oluşturabilirsiniz. Bazen düzgün çalışsa da, tarayıcı işlemenin başlangıcında en az bir kez 100.000 öğenin tümünü işlemeyi dener ve bu da tarayıcı sekmesinin kilitlenmesine neden olabilir.

.NET 7'nin yayımlanmasından önce bu soruna geçici bir çözüm bulmak için öğeleri stilden <html>/<body> overflow-y: scroll kaçının veya alternatif bir yaklaşım benimseyin. Aşağıdaki örnekte, öğesinin yüksekliği görünüm penceresi yüksekliğinin <html> %100'ünden biraz fazla olarak ayarlanmıştır:

<style>
    html { min-height: calc(100vh + 0.3px) }
</style>

Ara öğe etiketi adını denetleme

Virtualize<TItem> Bileşen belirli bir alt etiket adı gerektiren bir öğenin içine yerleştirilirse, SpacerElement sanallaştırma ara çubuğu etiket adını almanıza veya ayarlamanıza olanak tanır. Varsayılan değer şudur: div. Aşağıdaki örnekte, Virtualize<TItem> bileşen bir tablo gövdesi öğesi ()tbody içinde işlenir, bu nedenle tablo satırı (tr) için uygun alt öğe aralayıcı olarak ayarlanır.

VirtualizedTable.razor:

@page "/virtualized-table"

<PageTitle>Virtualized Table</PageTitle>

<HeadContent>
    <style>
        html, body {
            overflow-y: scroll
        }
    </style>
</HeadContent>

<h1>Virtualized Table Example</h1>

<table id="virtualized-table">
    <thead style="position: sticky; top: 0; background-color: silver">
        <tr>
            <th>Item</th>
            <th>Another column</th>
        </tr>
    </thead>
    <tbody>
        <Virtualize Items="fixedItems" ItemSize="30" SpacerElement="tr">
            <tr @key="context" style="height: 30px;" id="row-@context">
                <td>Item @context</td>
                <td>Another value</td>
            </tr>
        </Virtualize>
    </tbody>
</table>

@code {
    private List<int> fixedItems = Enumerable.Range(0, 1000).ToList();
}

Yukarıdaki örnekte, belge kökü kaydırma kapsayıcısı olarak kullanıldığından html ve body öğeleri ile overflow-y: scrollstillendirilir. Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın: