Condividi tramite


componente ASP.NET Core BlazorQuickGrid

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Il componente QuickGrid è un componente Razor per visualizzare i dati in modo rapido ed efficiente in formato tabulare. QuickGrid fornisce un componente griglia di dati semplice e pratico per scenari comuni di rendering della griglia e funge da architettura di riferimento e baseline delle prestazioni per la compilazione di componenti della griglia dati. QuickGrid è altamente ottimizzato e usa tecniche avanzate per ottenere prestazioni di rendering ottimali.

Pacchetto

Aggiungere un riferimento al pacchetto Microsoft.AspNetCore.Components.QuickGrid.

Nota

Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.

Esempio di app

Per varie dimostrazioni di QuickGrid, vedere le QuickGrid per l'app di esempio Blazor. Il sito demo è ospitato in GitHub Pages. Il sito si carica rapidamente grazie al prerendering statico utilizzando il progetto su GitHub mantenuto dalla community.

QuickGrid implementazione

Per implementare un QuickGrid componente:

  • Specificare i tag del componente QuickGrid nel markup Razor (<QuickGrid>...</QuickGrid>).
  • Assegnare un nome a un'origine di dati interrogabile per la griglia. Usare una delle origini dati seguenti:
    • Items: un valore annullabile IQueryable<TGridItem>, dove TGridItem è il tipo di dati rappresentato da ogni riga nella griglia.
    • ItemsProvider: Un callback che fornisce dati per la griglia.
  • Class: nome facoltativo della classe CSS. Se specificato, il nome della classe viene incluso nell'attributo class della tabella sottoposta a rendering.
  • Theme: nome del tema (valore predefinito: default). Ciò influisce sulle regole di stile che corrispondono alla tabella.
  • Virtualize: se impostato su vero, è eseguito il rendering della griglia con virtualizzazione. Di solito viene utilizzato insieme allo scorrimento e consente alla griglia di recuperare e visualizzare solo i dati attorno al viewport corrente di scorrimento. Ciò può migliorare notevolmente le prestazioni durante lo scorrimento tra set di dati di grandi dimensioni. Se si usa Virtualize, è necessario specificare un valore per ItemSize e assicurarsi che ogni riga esegua il rendering con un'altezza costante. In genere, è preferibile non usare Virtualize se la quantità di dati di cui è stato eseguito il rendering è ridotta o se si usa la paginazione.
  • ItemSize: applicabile solo quando si usa Virtualize. ItemSize definisce un'altezza prevista in pixel per ogni riga, consentendo al meccanismo di virtualizzazione di recuperare il numero corretto di elementi in modo che corrispondano alle dimensioni di visualizzazione e per garantire uno scorrimento accurato.
  • ItemKey: definisce facoltativamente un valore per @key in ogni riga sottoposta a rendering. In genere, viene usato per specificare un identificatore univoco, ad esempio un valore di chiave primaria, per ogni elemento di dati. Ciò consente alla griglia di mantenere l'associazione tra elementi di riga ed elementi di dati in base ai relativi identificatori univoci, anche quando le TGridItem istanze vengono sostituite da nuove copie, ad esempio dopo una nuova query sull'archivio dati sottostante. Se non è impostato, @key è l'istanza TGridItem.
  • OverscanCount: definisce il numero di elementi aggiuntivi di cui eseguire il rendering prima e dopo l'area visibile per ridurre la frequenza di rendering durante lo scorrimento. Anche se valori più elevati possono migliorare la fluidità dello scorrimento eseguendo il rendering di più elementi fuori schermo, un valore maggiore può anche comportare un aumento dei tempi di caricamento iniziali. È consigliabile trovare un equilibrio in base alle dimensioni del set di dati e ai requisiti dell'esperienza utente. Il valore predefinito è 3. Disponibile solo quando si usa Virtualize.
  • Pagination: Può collegare facoltativamente questa TGridItem istanza a un PaginationState modello, per fare in modo che la griglia recuperi e renda solo la pagina corrente dei dati. Viene in genere usato insieme a un Paginator componente o a un'altra logica dell'interfaccia utente che visualizza e aggiorna l'istanza fornita PaginationState .
  • Nel contenuto figlio (QuickGridRenderFragment), specificare PropertyColumn<TGridItem,TProp>, che rappresentano colonne le cui celle visualizzano i valori TGridItem:
    • Property: definisce il valore da visualizzare nelle celle di questa colonna.
    • Format: specifica facoltativamente una stringa di formato per il valore. Per usare Format è necessario che il TProp tipo implementi IFormattable.
    • Sortable: indica se i dati devono essere ordinabili in base a questa colonna. Il valore predefinito può variare in base al tipo di colonna. Ad esempio, un TemplateColumn<TGridItem> oggetto viene ordinato se viene specificato un SortBy parametro.
    • InitialSortDirection: indica la direzione di ordinamento se IsDefaultSortColumn è true.
    • IsDefaultSortColumn: indica se questa colonna deve essere ordinata per impostazione predefinita.
    • PlaceholderTemplate: se specificato, le griglie virtualizzate usano questo modello per eseguire il rendering delle celle i cui dati non sono stati caricati.
    • HeaderTemplate: modello facoltativo per la cella di intestazione di questa colonna. Se non specificato, il modello di intestazione predefinito include il Title, insieme agli indicatori di ordinamento applicabili e ai pulsanti delle opzioni.
    • Title: testo del titolo per la colonna. Il titolo è reso automaticamente se HeaderTemplate non viene utilizzato.
  • Specificare i tag del componente QuickGrid nel markup Razor (<QuickGrid>...</QuickGrid>).
  • Assegnare un nome a un'origine di dati interrogabile per la griglia. Usare una delle origini dati seguenti:
    • Items: un valore annullabile IQueryable<TGridItem>, dove TGridItem è il tipo di dati rappresentato da ogni riga nella griglia.
    • ItemsProvider: Un callback che fornisce dati per la griglia.
  • Class: nome facoltativo della classe CSS. Se specificato, il nome della classe viene incluso nell'attributo class della tabella sottoposta a rendering.
  • Theme: nome del tema (valore predefinito: default). Ciò influisce sulle regole di stile che corrispondono alla tabella.
  • Virtualize: se impostato su vero, è eseguito il rendering della griglia con virtualizzazione. Di solito viene utilizzato insieme allo scorrimento e consente alla griglia di recuperare e visualizzare solo i dati attorno al viewport corrente di scorrimento. Ciò può migliorare notevolmente le prestazioni durante lo scorrimento tra set di dati di grandi dimensioni. Se si usa Virtualize, è necessario specificare un valore per ItemSize e assicurarsi che ogni riga esegua il rendering con un'altezza costante. In genere, è preferibile non usare Virtualize se la quantità di dati di cui è stato eseguito il rendering è ridotta o se si usa la paginazione.
  • ItemSize: applicabile solo quando si usa Virtualize. ItemSize definisce un'altezza prevista in pixel per ogni riga, consentendo al meccanismo di virtualizzazione di recuperare il numero corretto di elementi in modo che corrispondano alle dimensioni di visualizzazione e per garantire uno scorrimento accurato.
  • ItemKey: definisce facoltativamente un valore per @key in ogni riga sottoposta a rendering. In genere, viene usato per specificare un identificatore univoco, ad esempio un valore di chiave primaria, per ogni elemento di dati. Ciò consente alla griglia di mantenere l'associazione tra elementi di riga ed elementi di dati in base ai relativi identificatori univoci, anche quando le TGridItem istanze vengono sostituite da nuove copie, ad esempio dopo una nuova query sull'archivio dati sottostante. Se non è impostato, @key è l'istanza TGridItem.
  • Pagination: Può collegare facoltativamente questa TGridItem istanza a un PaginationState modello, per fare in modo che la griglia recuperi e renda solo la pagina corrente dei dati. Viene in genere usato insieme a un Paginator componente o a un'altra logica dell'interfaccia utente che visualizza e aggiorna l'istanza fornita PaginationState .
  • Nel contenuto figlio (QuickGridRenderFragment), specificare PropertyColumn<TGridItem,TProp>, che rappresentano colonne le cui celle visualizzano i valori TGridItem:
    • Property: definisce il valore da visualizzare nelle celle di questa colonna.
    • Format: specifica facoltativamente una stringa di formato per il valore. Per usare Format è necessario che il TProp tipo implementi IFormattable.
    • Sortable: indica se i dati devono essere ordinabili in base a questa colonna. Il valore predefinito può variare in base al tipo di colonna. Ad esempio, un TemplateColumn<TGridItem> oggetto viene ordinato se viene specificato un SortBy parametro.
    • InitialSortDirection: indica la direzione di ordinamento se IsDefaultSortColumn è true.
    • IsDefaultSortColumn: indica se questa colonna deve essere ordinata per impostazione predefinita.
    • PlaceholderTemplate: se specificato, le griglie virtualizzate usano questo modello per eseguire il rendering delle celle i cui dati non sono stati caricati.
    • HeaderTemplate: modello facoltativo per la cella di intestazione di questa colonna. Se non specificato, il modello di intestazione predefinito include il Title, insieme agli indicatori di ordinamento applicabili e ai pulsanti delle opzioni.
    • Title: testo del titolo per la colonna. Il titolo è reso automaticamente se HeaderTemplate non viene utilizzato.

Ad esempio, aggiungere il componente seguente per eseguire il rendering di una griglia.

Per Blazor Web Apps, il componente QuickGrid deve adottare una modalità di rendering interattiva per abilitare funzionalità come il paging e l'ordinamento.

PromotionGrid.razor:

@page "/promotion-grid"
@using Microsoft.AspNetCore.Components.QuickGrid

<PageTitle>Promotion Grid</PageTitle>

<h1>Promotion Grid Example</h1>

<QuickGrid Items="people">
    <PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
    <PropertyColumn Property="@(p => p.Name)" Sortable="true" />
    <PropertyColumn Property="@(p => p.PromotionDate)" Format="yyyy-MM-dd" Sortable="true" />
</QuickGrid>

@code {
    private record Person(int PersonId, string Name, DateOnly PromotionDate);

    private IQueryable<Person> people = new[]
    {
        new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)),
        new Person(10944, "António Langa", new DateOnly(1991, 12, 1)),
        new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)),
        new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)),
        new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)),
        new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)),
    }.AsQueryable();
}
@page "/promotion-grid"
@using Microsoft.AspNetCore.Components.QuickGrid

<PageTitle>Promotion Grid</PageTitle>

<h1>Promotion Grid Example</h1>

<QuickGrid Items="people">
    <PropertyColumn Property="@(p => p.PersonId)" Sortable="true" />
    <PropertyColumn Property="@(p => p.Name)" Sortable="true" />
    <PropertyColumn Property="@(p => p.PromotionDate)" Format="yyyy-MM-dd" Sortable="true" />
</QuickGrid>

@code {
    private record Person(int PersonId, string Name, DateOnly PromotionDate);

    private IQueryable<Person> people = new[]
    {
        new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)),
        new Person(10944, "António Langa", new DateOnly(1991, 12, 1)),
        new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)),
        new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)),
        new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)),
        new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)),
    }.AsQueryable();
}

Accedere al componente in un browser al percorso relativo /promotion-grid.

Non ci sono piani attuali per estendere QuickGrid con funzionalità che le griglie commerciali complete tendono a offrire, ad esempio, righe gerarchiche, colonne riordinabili tramite trascinamento o selezioni di intervalli simili a quelle di Excel. Se sono necessarie funzionalità avanzate che non si desidera sviluppare autonomamente, continuare a usare griglie di terze parti.

Ordina per colonna

Il QuickGrid componente può ordinare gli elementi in base alle colonne. In Blazor Web Apps, l'ordinamento richiede al componente di adottare una modalità di rendering interattiva.

Aggiungere Sortable="true" (Sortable) al PropertyColumn<TGridItem,TProp> tag:

<PropertyColumn Property="..." Sortable="true" />

Nell'app in esecuzione, ordina la colonna QuickGrid selezionando il titolo della colonna visualizzata.

Elementi di pagina con un Paginator componente

Il componente QuickGrid può paginare i dati dalla fonte dati. In Blazor Web Apps, il paging richiede al componente di adottare una modalità di rendering interattiva.

Aggiungere un'istanza PaginationState al blocco @code del componente. Impostare il ItemsPerPage sul numero di elementi da visualizzare per pagina. Nell'esempio seguente l'istanza è denominata paginatione vengono impostati dieci elementi per pagina:

PaginationState pagination = new PaginationState { ItemsPerPage = 10 };

Impostare la QuickGrid proprietà del Pagination componente su pagination:

<QuickGrid Items="..." Pagination="pagination">

Per fornire un'interfaccia utente per la paginazione, aggiungere un Paginator componente sopra o sotto il QuickGrid componente. Impostare il Paginator.State su pagination:

<Paginator State="pagination" />

Nell'app, scorrere gli elementi usando un componente Paginator renderizzato.

QuickGrid esegue il rendering di righe vuote aggiuntive per riempire la pagina finale dei dati quando usato con un componente Paginator. In .NET 9 o versione successiva le celle di dati vuote (<td></td>) vengono aggiunte alle righe vuote. Le righe vuote sono concepite per facilitare il rendering del QuickGrid con altezza di riga stabile e uno stile coerente su tutte le pagine.

Applicare gli stili di riga

Applicare stili alle righe utilizzando l'isolamento CSS, che può includere lo stile delle righe vuote per i componenti che impaginano i dati con un componente .

Avvolgere il componente QuickGrid in un elemento wrapper di blocco, ad esempio un <div>:

+ <div>
    <QuickGrid ...>
        ...
    </QuickGrid>
+ </div>

Applicare uno stile di riga con lo pseudoelemento ::deep. Nell'esempio seguente l'altezza della riga è impostata su 2em, incluso per le righe di dati vuote.

{COMPONENT}.razor.css:

::deep tr {
    height: 2em;
}

In alternativa, usare l'approccio di stile CSS seguente:

  • Visualizzare le celle di riga popolate con i dati.
  • Non visualizzare celle di riga vuote, il che evita che i bordi delle celle di riga vuote vengano visualizzati a causa dello stile Bootstrap.

{COMPONENT}.razor.css:

::deep tr:has(> td:not(:empty)) > td {
    display: table-cell;
}

::deep td:empty {
    display: none;
}

Per ulteriori informazioni sull'uso dei pseudo-elementi ::deep con l'isolamento CSS, vedere ASP.NET Core Blazor isolamento CSS.

Attributi e stili personalizzati

QuickGrid supporta anche il passaggio di attributi personalizzati e classi di stile (Class) all'elemento tabella di cui è stato eseguito il rendering:

<QuickGrid Items="..." custom-attribute="value" Class="custom-class">

Applicare uno stile a una riga di tabella in base al contenuto della riga

Applicare una classe del foglio di stile a una riga della griglia in base all'elemento di riga utilizzando il parametro RowClass.

Nell'esempio seguente:

  • Un elemento di riga è rappresentato dal record Person. Il record Person include una proprietà FirstName.
  • Il metodo GetRowCssClass applica gli stili di classe highlight-row a qualsiasi riga in cui il nome della persona è "Julie".
<QuickGrid ... RowClass="GetRowCssClass">
    ...
</QuickGrid>

@code {
    private record Person(int PersonId, string FirstName, string LastName);

    private string GetRowCssClass(Person person) =>
        person.FirstName == "Julie" ? "highlight-row" : null;
}

Chiudere le opzioni della colonna QuickGrid

Chiudere l'interfaccia utente delle opzioni della colonna QuickGrid con il metodo HideColumnOptionsAsync.

L'esempio seguente chiude l'interfaccia utente delle opzioni di colonna non appena viene applicato il filtro del titolo:

<QuickGrid @ref="movieGrid" Items="movies">
    <PropertyColumn Property="@(m => m.Title)" Title="Title">
        <ColumnOptions>
            <input type="search" @bind="titleFilter" placeholder="Filter by title" 
                @bind:after="@(() => movieGrid.HideColumnOptionsAsync())" />
        </ColumnOptions>
    </PropertyColumn>
    <PropertyColumn Property="@(m => m.Genre)" Title="Genre" />
    <PropertyColumn Property="@(m => m.ReleaseYear)" Title="Release Year" />
</QuickGrid>

@code {
    private QuickGrid<Movie>? movieGrid;
    private string titleFilter = string.Empty;
    private IQueryable<Movie> movies = new List<Movie> { ... }.AsQueryable();
    private IQueryable<Movie> filteredMovies => 
        movies.Where(m => m.Title!.Contains(titleFilter));
}

Fonte dati di Entity Framework Core (EF Core)

Usare il modello factory per risolvere un EF Core contesto di database che fornisce dati a una componente QuickGrid. Per altre informazioni sul motivo per cui è consigliabile usare il modello factory, vedere ASP.NET Core con Entity Framework Core ().For more information on why the factory pattern is recommended, see ASP.NET Core Blazor with Entity Framework Core (EF Core).

Una factory del contesto database (IDbContextFactory<TContext>) è iniettata nel componente con la direttiva @inject. L'approccio factory richiede la dismissione del contesto del database, quindi il componente implementa l'interfaccia IAsyncDisposable con la direttiva @implements. Il provider di elementi per il componente QuickGrid è un DbSet<T> ottenuto dal contesto di database creato (CreateDbContext) della factory del contesto di database iniettata.

QuickGrid riconosce le istanze IQueryable fornite da EF e sa come risolvere le query in modo asincrono per ottenere efficienza.

Aggiungere un riferimento al Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter pacchetto NuGet.

Nota

Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.

Chiamare AddQuickGridEntityFrameworkAdapter nella collezione di servizi nel file Program per registrare un'implementazione compatibile con Entity Framework IAsyncQueryExecutor.

builder.Services.AddQuickGridEntityFrameworkAdapter();

Nell'esempio seguente viene usata una ExampleTableDbSet<TEntity> (tabella) da un AppDbContext contesto di database (context) come origine dati per un QuickGrid componente:

@using Microsoft.AspNetCore.Components.QuickGrid
@using Microsoft.EntityFrameworkCore
@implements IAsyncDisposable
@inject IDbContextFactory<AppDbContext> DbFactory

...

<QuickGrid ... Items="context.ExampleTable" ...>
    ...
</QuickGrid>

@code {
    private AppDbContext context = default!;

    protected override void OnInitialized()
    {
        context = DbFactory.CreateDbContext();
    }

    public async ValueTask DisposeAsync() => await context.DisposeAsync();
}

Nel blocco di codice (@code) dell'esempio precedente:

  • Il context campo contiene il contesto del database, digitato come .AppDbContext
  • Il metodo OnInitialized del ciclo di vita assegna un nuovo contesto di database (CreateDbContext) al campo context dalla fabbrica inserita (DbFactory).
  • Il metodo asincrono DisposeAsync elimina il contesto del database quando il componente viene eliminato.

È anche possibile usare qualsiasi operatore LINQ supportato da EF per filtrare i dati prima di passarli al Items parametro .

L'esempio seguente filtra i film in base al titolo di un film immesso in una casella di ricerca. Il contesto del database è BlazorWebAppMoviesContexte il modello è Movie. La proprietà del Title film viene utilizzata per l'operazione di filtro.

@using Microsoft.AspNetCore.Components.QuickGrid
@using Microsoft.EntityFrameworkCore
@implements IAsyncDisposable
@inject IDbContextFactory<BlazorWebAppMoviesContext> DbFactory

...

<p>
    <input type="search" @bind="titleFilter" @bind:event="oninput" />
</p>

<QuickGrid ... Items="FilteredMovies" ...>
    ...
</QuickGrid>

@code {
    private string titleFilter = string.Empty;
    private BlazorWebAppMoviesContext context = default!;

    protected override void OnInitialized()
    {
        context = DbFactory.CreateDbContext();
    }

    private IQueryable<Movie> FilteredMovies => 
        context.Movie.Where(m => m.Title!.Contains(titleFilter));

    public async ValueTask DisposeAsync() => await context.DisposeAsync();
}

Per un esempio funzionante, vedere le risorse seguenti:

Supporto per i nomi visualizzati

È possibile assegnare un titolo di colonna usando ColumnBase<TGridItem>.Title nel tag di PropertyColumn<TGridItem,TProp>. Nell'esempio di film seguente, alla colonna viene assegnato il nome "Release Date" per i dati relativi alla data di uscita del film:

<PropertyColumn Property="movie => movie.ReleaseDate" Title="Release Date" />

Tuttavia, gestire i titoli delle colonne (nomi) dalle proprietà del modello associato è in genere una scelta migliore per mantenere un'app. Un modello può controllare il nome visualizzato di una proprietà con l'attributo [Display]. Nell'esempio seguente, il modello specifica per la sua proprietà Release Date il nome visualizzato della "data di uscita del film" "ReleaseDate".

[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }

Per consentire al componente QuickGrid di utilizzare la proprietà DisplayAttribute.Name, la sottoclasse PropertyColumn<TGridItem,TProp>, nel componente o in una classe separata. Chiamare il metodo GetName per restituire il valore DisplayAttribute.Name localizzato se un DisplayName non localizzato ([DisplayName] attributo) non contiene il valore :

public class DisplayNameColumn<TGridItem, TProp> : PropertyColumn<TGridItem, TProp>
{
    protected override void OnParametersSet()
    {
        if (Title is null && Property.Body is MemberExpression memberExpression)
        {
            var memberInfo = memberExpression.Member;
            Title = 
                memberInfo.GetCustomAttribute<DisplayNameAttribute>().DisplayName ??
                memberInfo.GetCustomAttribute<DisplayAttribute>().GetName() ??
                memberInfo.Name;
        }

        base.OnParametersSet();
    }
}

Usare la sottoclasse nel QuickGrid componente. Nell'esempio seguente viene usato il precedente DisplayNameColumn . Il nome "" viene fornito dall'attributo nel modello, quindi non è necessario specificare un oggetto:

<DisplayNameColumn Property="movie => movie.ReleaseDate" />

L'attributo [DisplayName] è supportato anche:

[DisplayName("Release Date")]
public DateTime ReleaseDate { get; set; }

Tuttavia, l'attributo [Display] è consigliato perché rende disponibili proprietà aggiuntive. Ad esempio, l'attributo [Display] offre la possibilità di assegnare un tipo di risorsa per la localizzazione.

Dati remoti

Nelle Blazor WebAssembly app, il recupero di dati da un'API Web basata su JSON in un server è un requisito comune. Per recuperare solo i dati necessari per la pagina/viewport corrente dei dati e applicare regole di ordinamento o filtro nel server, usare il ItemsProvider parametro .

ItemsProvider può essere usato anche in un'app Blazor lato server se l'app deve eseguire query su un endpoint esterno o in altri casi in cui i requisiti non sono coperti da un oggetto IQueryable.

Fornire un callback corrispondente al GridItemsProvider<TGridItem> tipo delegato, dove TGridItem è il tipo di dati visualizzato nella griglia. Al callback viene assegnato un parametro di tipo GridItemsProviderRequest<TGridItem>, che specifica l'indice iniziale, il numero massimo di righe e l'ordinamento dei dati da restituire. Oltre a restituire gli elementi corrispondenti, è necessario anche un conteggio totale degli elementi (totalItemCount) per il corretto funzionamento del paging e della virtualizzazione.

Nell'esempio seguente vengono ottenuti dati dal database pubblico OpenFDA Food Enforcement.

GridItemsProvider<TGridItem> converte il GridItemsProviderRequest<TGridItem> in una query sul database OpenFDA. I parametri di query vengono convertiti nel formato url specifico supportato dall'API JSON esterna. È possibile eseguire l'ordinamento e il filtro solo tramite l'ordinamento e il filtro supportati dall'API esterna. L'endpoint OpenFDA non supporta l'ordinamento, quindi nessuna delle colonne viene contrassegnata come ordinabile. Tuttavia, supporta l'omissione di record (skip parametro) e la limitazione della restituzione di record (limit parametro ), in modo che il componente possa abilitare la virtualizzazione e scorrere rapidamente decine di migliaia di record.

FoodRecalls.razor:

@page "/food-recalls"
@inject HttpClient Http
@inject NavigationManager Navigation

<PageTitle>Food Recalls</PageTitle>

<h1>OpenFDA Food Recalls</h1>

<div class="grid" tabindex="-1">
    <QuickGrid ItemsProvider="@foodRecallProvider" Virtualize="true">
        <PropertyColumn Title="ID" Property="@(c => c.Event_Id)" />
        <PropertyColumn Property="@(c => c.State)" />
        <PropertyColumn Property="@(c => c.City)" />
        <PropertyColumn Title="Company" Property="@(c => c.Recalling_Firm)" />
        <PropertyColumn Property="@(c => c.Status)" />
    </QuickGrid>
</div>

<p>Total: <strong>@numResults results found</strong></p>

@code {
    private GridItemsProvider<FoodRecall>? foodRecallProvider;
    private int numResults;

    protected override async Task OnInitializedAsync()
    {
        foodRecallProvider = async req =>
        {
            var url = Navigation.GetUriWithQueryParameters(
                "https://api.fda.gov/food/enforcement.json", 
                new Dictionary<string, object?>
            {
                { "skip", req.StartIndex },
                { "limit", req.Count },
            });

            using var response = await Http.GetFromJsonAsync<FoodRecallQueryResult>(
                url, req.CancellationToken);

            return GridItemsProviderResult.From(
                items: response!.Results,
                totalItemCount: response!.Meta.Results.Total);
        };

        numResults = (await Http.GetFromJsonAsync<FoodRecallQueryResult>(
            "https://api.fda.gov/food/enforcement.json"))!.Meta.Results.Total;
    }
}

Per ulteriori informazioni sulla chiamata di API Web, consultare Chiamare un'API Web da un'app ASP.NET CoreBlazor.

QuickGrid montatore di ponteggi

Il QuickGrid scaffolder configura i Razor componenti con QuickGrid per visualizzare i dati da un database.

Lo scaffolder genera pagine CRUD di base basate su un modello di dati di Entity Framework Core. È possibile eseguire lo scaffolding di singole pagine o di tutte le pagine CRUD. Selezioni la classe del modello e DbContext, opzionalmente creando un nuovo DbContext se necessario.

I componenti scaffoldati Razor vengono aggiunti al progetto in una cartella generata denominata con il nome della classe del modello. Il componente generato Index usa un QuickGrid componente per visualizzare i dati. Personalizzare i componenti generati in base alle esigenze e abilitare l'interattività per sfruttare le funzionalità interattive, ad esempio il paging, l'ordinamento e il filtro.

I componenti prodotti dallo scaffolder richiedono il rendering lato server (SSR), quindi non sono supportati durante l'esecuzione in WebAssembly.

Fare clic con il pulsante destro del mouse sulla Components/Pages cartella e scegliere Aggiungi>Nuovo Elemento con Scaffold.

Con la finestra di dialogo Aggiungi nuovo elemento di scaffolding aperta a InstallatoComponente comune, selezionare Componenti usando Entity Framework (CRUD). Seleziona il pulsante Aggiungi.

CRUD è l'acronimo di Create, Read, Update e Delete. Lo scaffolder produce componenti di creazione, modifica, eliminazione, dettagli e indice per l'app.

Completare la finestra di dialogo Aggiungi componenti Razor usando Entity Framework (CRUD):

  • L'elenco a discesa Modello include altri modelli specifici per creare, modificare, eliminare, visualizzare dettagli e gestire componenti di elenco. Questo elenco a discesa risulta utile solo quando è sufficiente creare un tipo specifico di componente sottoposto a scaffolding in una classe modello. Lasciare l'elenco Modello a discesa impostato su CRUD per creare lo scaffolding di un set completo di componenti.
  • Nell'elenco a discesa Classe modello selezionare la classe del modello. Viene creata una cartella per i componenti generati dal nome del modello (se la classe del modello è denominata Movie, la cartella viene automaticamente denominata MoviePages).
  • Per classe DbContext, adottare uno degli approcci seguenti:
    • Selezionare un'esistente classe di DbContext che si sa avere una registrazione del fornitore di fabbrica (AddDbContextFactory).
    • Selezionare il pulsante + (segno più) e usare la finestra di dialogo modale Aggiungi contesto dati per specificare un nuovo nome di classe DbContext, che registra la classe con un provider di fabbrica invece di utilizzare direttamente il tipo di contesto come registrazione del servizio.
  • Dopo la chiusura della finestra di dialogo del modello, l'elenco a discesa Provider di database viene impostato su SQL Server per impostazione predefinita. È possibile selezionare il provider appropriato per il database in uso. Le opzioni includono SQL Server, SQLite, PostgreSQL e Azure Cosmos DB.
  • Selezionare Aggiungi.

Per un esempio di uso dello QuickGrid scaffolder, guarda Blazor

Più query simultanee EF Core attivano System.InvalidOperationException

Più query EF Core simultanee possono attivare le seguenti System.InvalidOperationException:

System.InvalidOperationException: una seconda operazione è stata avviata in questa istanza di contesto prima del completamento di un'operazione precedente. Ciò è in genere causato da thread diversi contemporaneamente che usano la stessa istanza di DbContext. Per altre informazioni su come evitare problemi di threading con DbContext, vedere https://go.microsoft.com/fwlink/?linkid=2097913.

Questo scenario è pianificato per il miglioramento in una versione futura di ASP.NET Core. Per altre informazioni, vedere [Blazor] Migliorare l'esperienza con QuickGrid e EF Core (dotnet/aspnetcore #58716).

Nel frattempo, è possibile risolvere il problema usando un ItemsProvider con un token di annullamento. Il token di annullamento impedisce query simultanee annullando la richiesta precedente quando viene emessa una nuova richiesta.

Si consideri il seguente esempio, basato sul database del film componente Index per l'esercitazione di creazione di un'app di database di film Blazor (Panoramica). La versione più semplice integrata nell'app può essere visualizzata sull'app di esempio dell'articolo. Il componente Index generato tramite scaffolding nell'app viene sostituito dal seguente componente.

Components/Pages/MoviePages/Index.razor:

@page "/movies"
@rendermode InteractiveServer
@using Microsoft.EntityFrameworkCore
@using Microsoft.AspNetCore.Components.QuickGrid
@using BlazorWebAppMovies.Models
@using BlazorWebAppMovies.Data
@inject IDbContextFactory<BlazorWebAppMovies.Data.BlazorWebAppMoviesContext> DbFactory

<PageTitle>Index</PageTitle>

<h1>Index</h1>

<div>
    <input type="search" @bind="titleFilter" @bind:event="oninput" />
</div>

<p>
    <a href="movies/create">Create New</a>
</p>

<div>
    <QuickGrid Class="table" TGridItem="Movie" ItemsProvider="GetMovies"
            ItemKey="(x => x.Id)" Pagination="pagination">
        <PropertyColumn Property="movie => movie.Title" Sortable="true" />
        <PropertyColumn Property="movie => movie.ReleaseDate" Title="Release Date" />
        <PropertyColumn Property="movie => movie.Genre" />
        <PropertyColumn Property="movie => movie.Price" />
        <PropertyColumn Property="movie => movie.Rating" />

        <TemplateColumn Context="movie">
            <a href="@($"movies/edit?id={movie.Id}")">Edit</a> |
            <a href="@($"movies/details?id={movie.Id}")">Details</a> |
            <a href="@($"movies/delete?id={movie.Id}")">Delete</a>
        </TemplateColumn>
    </QuickGrid>
</div>

<Paginator State="pagination" />

@code {
    private BlazorWebAppMoviesContext context = default!;
    private PaginationState pagination = new PaginationState { ItemsPerPage = 5 };
    private string titleFilter = string.Empty;

    public async ValueTask<GridItemsProviderResult<Movie>> GetMovies(GridItemsProviderRequest<Movie> request)
    {
        using var context = DbFactory.CreateDbContext();
        var totalCount = await context.Movie.CountAsync(request.CancellationToken);
        IQueryable<Movie> query = context.Movie.OrderBy(x => x.Id);
        query = request.ApplySorting(query).Skip(request.StartIndex);

        if (request.Count.HasValue)
        {
            query = query.Take(request.Count.Value);
        }

        var items = await query.ToArrayAsync(request.CancellationToken);

        var result = new GridItemsProviderResult<Movie>
        {
            Items = items,
            TotalItemCount = totalCount
        };

        return result;
    }
}