Partage via


composant ASP.NET Core BlazorQuickGrid

Remarque

Ceci n'est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.

Importante

Ces informations portent sur une version préliminaire du produit, qui pourrait être largement modifié avant sa commercialisation. Microsoft n'offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 9 de cet article.

Le composant QuickGrid est un composant Razor pour afficher rapidement et efficacement les données sous forme tabulaire. QuickGridfournit un composant de grille de données simple et pratique pour les scénarios de rendu de grille les plus courants et sert d'architecture de référence et de base de performance pour la construction de composants de grille de données. QuickGrid est hautement optimisé et utilise des techniques avancées pour obtenir des performances de rendu optimales.

Paquet

Ajoutez une référence de package pour le package Microsoft.AspNetCore.Components.QuickGrid

Remarque

Pour obtenir des conseils sur l'ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Exemple d'application

Pour différentes démonstrations de QuickGrid, consultez l’exemple d’application QuickGrid pour Blazor. Le site de démonstration est hébergé sur GitHub Pages. Le site se charge rapidement grâce à un pré-rendu statique utilisant le BlazorWasmPrerendering.Buildprojet GitHub maintenu par la communauté.

Mise en œuvre de QuickGrid

Pour implémenter un composant QuickGrid :

  • Spécifiez des balises pour le composant QuickGrid dans le balisage Razor (<QuickGrid>...</QuickGrid>).
  • Nommez une source interrogeable de données pour la grille. Utilisez l'une des sources de données suivantes :
    • Items : Un IQueryable<TGridItem> nullable, où TGridItem est le type de données représenté par chaque ligne de la grille.
    • ItemsProvider : Un callback qui fournit des données à la grille.
  • Class : Un nom de classe CSS facultatif. S'il est fourni, le nom de la classe est inclus dans l'attribut class de la table affichée.
  • Theme : Un nom de thème (valeur par défaut : default). Cela affecte les règles de style qui correspondent à la table.
  • Virtualize : S'il est vrai, la grille est affichée avec virtualisation. Cela est habituellement utilisé conjointement avec le défilement et fait en sorte que la grille n'extrait et n'affiche que les données autour de la fenêtre d'affichage de défilement actuelle. Cela peut considérablement améliorer les performances lors du défilement de jeux de données volumineux. Si vous utilisez Virtualize, vous devez fournir une valeur pour ItemSize et devez vous assurer que chaque ligne s'affiche avec une hauteur constante. En règle générale, il est préférable de ne pas utiliser Virtualize si la quantité de données affichées est petite ou si vous utilisez la pagination.
  • ItemSize : Uniquement applicable lors de l'utilisation de Virtualize. ItemSize définit une hauteur attendue en pixels pour chaque ligne, ce qui permet au mécanisme de virtualisation de récupérer le nombre correct d'éléments en fonction de la taille de l'affichage et d'assurer un défilement précis.
  • ItemKey : Définit optionnellement une valeur pour @key sur chaque ligne rendue. En règle générale, il est utilisé pour spécifier un identificateur unique, tel qu'une valeur de clé primaire, pour chaque élément de données. Cela permet à la grille de conserver l'association entre les éléments de ligne et les éléments de données en fonction de leurs identificateurs uniques, même lorsque les instances TGridItem sont remplacées par de nouvelles copies (par exemple, après une nouvelle requête sur le magasin de données sous-jacent). S'il n'est pas défini, @key est l'instance TGridItem.
  • OverscanCount : Définit le nombre d'éléments supplémentaires à rendre avant et après la région visible afin de réduire la fréquence de rendu lors du défilement. Si des valeurs élevées peuvent améliorer la fluidité du défilement en rendant plus d'éléments en dehors de l'écran, elles peuvent également entraîner une augmentation des temps de chargement initiaux. Il est recommandé de trouver un équilibre en fonction de la taille de votre ensemble de données et des exigences de l'utilisateur. La valeur par défaut est 3. Uniquement disponible lorsque vous utilisez Virtualize.
  • Pagination : Lier optionnellement cette instance TGridItem à un modèle PaginationState, afin que la grille ne récupère et ne rende que les données de la page en cours. Cela est habituellement utilisé conjointement avec un composant Paginator ou une autre logique d'interface utilisateur qui affiche et met à jour l'instance PaginationState fournie.
  • Dans le contenu enfant QuickGrid (RenderFragment), spécifiez PropertyColumn<TGridItem,TProp>s, qui représentent des colonnes TGridItem dont les cellules affichent les valeurs :
    • Property : Définit la valeur à afficher dans les cellules de cette colonne.
    • Format : Spécifie optionnellement une chaîne de format pour la valeur. Utiliser Format nécessite que le type TProp implémente IFormattable.
    • Sortable : Indique si les données doivent être triées en fonction de cette colonne. La valeur par défaut peut varier en fonction du type de colonne. Par exemple, un TemplateColumn<TGridItem> est trié si un paramètre SortBy est spécifié.
    • InitialSortDirection : Indique le sens de tri si IsDefaultSortColumn est true.
    • IsDefaultSortColumn : Indique si cette colonne doit être triée par défaut.
    • PlaceholderTemplate : Si spécifié, les grilles virtualisées utilisent ce modèle pour rendre les cellules dont les données n'ont pas été chargées.
    • HeaderTemplate : Un modèle facultatif pour la cellule d'en-tête de cette colonne. S'il n'est pas spécifié, le modèle d'en-tête par défaut inclut le Title, ainsi que les indicateurs de tri et les boutons d'options applicables.
    • Title : Le texte du titre de la colonne. Le titre est rendu automatiquement si HeaderTemplate n'est pas utilisé.
  • Spécifiez des balises pour le composant QuickGrid dans le balisage Razor (<QuickGrid>...</QuickGrid>).
  • Nommez une source interrogeable de données pour la grille. Utilisez l'une des sources de données suivantes :
    • Items : Un IQueryable<TGridItem> nullable, où TGridItem est le type de données représenté par chaque ligne de la grille.
    • ItemsProvider : Un callback qui fournit des données à la grille.
  • Class : Un nom de classe CSS facultatif. S'il est fourni, le nom de la classe est inclus dans l'attribut class de la table affichée.
  • Theme : Un nom de thème (valeur par défaut : default). Cela affecte les règles de style qui correspondent à la table.
  • Virtualize : Si c'est vrai, la grille est affichée avec virtualisation. Cela est habituellement utilisé conjointement avec le défilement et fait en sorte que la grille n'extrait et n'affiche que les données autour de la fenêtre d'affichage de défilement actuelle. Cela peut considérablement améliorer les performances lors du défilement de jeux de données volumineux. Si vous utilisez Virtualize, vous devez fournir une valeur pour ItemSize et devez vous assurer que chaque ligne s'affiche avec une hauteur constante. En règle générale, il est préférable de ne pas utiliser Virtualize si la quantité de données affichées est petite ou si vous utilisez la pagination.
  • ItemSize : Uniquement applicable lors de l'utilisation de Virtualize. ItemSize définit une hauteur attendue en pixels pour chaque ligne, ce qui permet au mécanisme de virtualisation de récupérer le nombre correct d'éléments en fonction de la taille de l'affichage et d'assurer un défilement précis.
  • ItemKey : Définit optionnellement une valeur pour @key sur chaque ligne rendue. En règle générale, il est utilisé pour spécifier un identificateur unique, tel qu'une valeur de clé primaire, pour chaque élément de données. Cela permet à la grille de conserver l'association entre les éléments de ligne et les éléments de données en fonction de leurs identificateurs uniques, même lorsque les instances TGridItem sont remplacées par de nouvelles copies (par exemple, après une nouvelle requête sur le magasin de données sous-jacent). S'il n'est pas défini, @key est l'instance TGridItem.
  • Pagination : Lier optionnellement cette instance TGridItem à un modèle PaginationState, afin que la grille ne récupère et ne rende que les données de la page en cours. Cela est habituellement utilisé conjointement avec un composant Paginator ou une autre logique d'interface utilisateur qui affiche et met à jour l'instance PaginationState fournie.
  • Dans le contenu enfant QuickGrid (RenderFragment), spécifiez PropertyColumn<TGridItem,TProp>s, qui représentent des colonnes TGridItem dont les cellules affichent les valeurs :
    • Property : Définit la valeur à afficher dans les cellules de cette colonne.
    • Format : Spécifie optionnellement une chaîne de format pour la valeur. Utiliser Format nécessite que le type TProp implémente IFormattable.
    • Sortable : Indique si les données doivent être triées en fonction de cette colonne. La valeur par défaut peut varier en fonction du type de colonne. Par exemple, un TemplateColumn<TGridItem> est trié si un paramètre SortBy est spécifié.
    • InitialSortDirection : Indique le sens de tri si IsDefaultSortColumn est true.
    • IsDefaultSortColumn : Indique si cette colonne doit être triée par défaut.
    • PlaceholderTemplate : Si spécifié, les grilles virtualisées utilisent ce modèle pour rendre les cellules dont les données n'ont pas été chargées.
    • HeaderTemplate : Un modèle facultatif pour la cellule d'en-tête de cette colonne. S'il n'est pas spécifié, le modèle d'en-tête par défaut inclut le Title, ainsi que les indicateurs de tri et les boutons d'options applicables.
    • Title : Le texte du titre de la colonne. Le titre est rendu automatiquement si HeaderTemplate n'est pas utilisé.

Par exemple, ajoutez le composant suivant pour afficher une grille.

Pour Blazor Web Apps, le composant QuickGrid doit adopter un mode de rendu interactif afin d'activer les fonctionnalités interactives, telles que la pagination et le tri.

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();
}

Accédez au composant dans un navigateur au chemin relatif /promotion-grid.

Il n'existe actuellement pas de plans pour étendre QuickGrid avec des fonctionnalités que les grilles commerciales complètes offrent habituellement, comme des lignes hiérarchiques, des colonnes réorganisables par glisser-déposer ou des sélections de plages de type Excel. Si vous avez besoin de fonctionnalités avancées que vous ne souhaitez pas développer par vous-même, continuez à utiliser des grilles tierces.

Trier par colonne

Le composant QuickGrid permet de trier les éléments par colonnes. Dans Blazor Web Apps, le tri exige que le composant adopte un mode de rendu interactif.

Ajoutez Sortable="true" (Sortable) à la balise PropertyColumn<TGridItem,TProp> :

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

Dans l'application en cours, triez la colonne QuickGrid en sélectionnant le titre de la colonne rendue.

Eléments de la page avec un composant Paginator.

Le composant QuickGrid peut mettre en page des données à partir de la source de données. Dans Blazor Web Apps, la pagination nécessite que le composant adopte un mode de rendu interactif.

Ajoutez une instance PaginationState au bloc @code du composant. Réglez le ItemsPerPage sur le nombre d'éléments à afficher par page. Dans l'exemple suivant, l'instance est nommée pagination et le nombre d'éléments par page est fixé à dix :

PaginationState pagination = new PaginationState { ItemsPerPage = 10 };

Définissez la propriété QuickGrid du composant Pagination à pagination :

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

Pour fournir une interface utilisateur pour la pagination, ajoutez un composant Paginator au-dessus ou au-dessous du composant QuickGrid. Réglez le Paginator.State sur pagination :

<Paginator State="pagination" />

Dans l'application en cours d'exécution, parcourez les éléments à l'aide d'un composant Paginator rendu.

QuickGrid affiche des lignes vides supplémentaires pour remplir la page finale des données lorsqu’elles sont utilisées avec un composant Paginator. Dans .NET 9 ou une version ultérieure, des cellules de données vides (<td></td>) sont ajoutées aux lignes vides. Les lignes vides sont destinées à faciliter le rendu du QuickGrid avec une hauteur de ligne stable et un style sur toutes les pages.

Appliquer des styles aux lignes

Appliquez des styles aux lignes en utilisant l'isolation CSS, ce qui peut inclure la mise en forme des lignes vides pour des composants QuickGrid qui paginent les données grâce à un composant Paginator.

Encapsulez le composant QuickGrid dans un élément de bloc enveloppant, par exemple une <div> :

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

Appliquez un style de ligne avec le ::deeppseudo-élément. Dans l’exemple suivant, la hauteur des lignes est fixée à 2em, y compris pour les lignes de données vides.

{COMPONENT}.razor.css :

::deep tr {
    height: 2em;
}

Sinon, utilisez l’approche de mise en forme CSS suivante :

  • Afficher les cellules de ligne remplies avec des données.
  • N'affichez pas les cellules de lignes vides, ce qui évite l'affichage des bordures des cellules de lignes vides selon le style Bootstrap.

{COMPONENT}.razor.css :

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

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

Pour plus d’informations sur l’utilisation des pseudo-éléments ::deep avec l’isolation CSS, consultez ASP.NET Core isolation CSS Blazor.

Attributs et styles personnalisés

QuickGrid prend également en charge le passage d’attributs personnalisés et de classes de style (Class) à l’élément de table rendu :

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

Style d'une ligne de tableau en fonction de l'élément de ligne

Appliquez une classe de feuille de style à une ligne de la grille en fonction de l’élément de ligne à l’aide du paramètre RowClass.

Dans l’exemple suivant :

  • Un élément de ligne est représenté par un Personenregistrement. L'enregistrement Person comprend une propriété FirstName.
  • La méthode GetRowCssClass applique les styles de classe highlight-row à n’importe quelle ligne où le prénom de la personne est «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;
}

Source de données Entity Framework Core (EF Core)

Utilisez le modèle de fabrique pour résoudre un contexte de base de données EF Core qui fournit des données à un composant QuickGrid. Pour plus d'informations sur les raisons pour lesquelles le motif de fabrique est recommandé, consultez ASP.NET CoreBlazor avec Entity Framework Core (EF Core).

Une fabrique de contexte de base de données (IDbContextFactory<TContext>) est injectée dans le composant avec la directive @inject. L'approche de la fabrique nécessite de disposer du contexte de la base de données, de sorte que le composant implémente l'interface IAsyncDisposable avec la directive @implements. Le fournisseur d'éléments pour le composant QuickGrid est un DbSet<T> obtenu à partir du contexte de base de données créé (CreateDbContext) de l'usine de contexte de base de données injectée.

QuickGrid reconnaît les instances de IQueryable fournies par EF et sait comment résoudre les requêtes de manière asynchrone pour obtenir de l’efficacité.

Ajoutez une référence au package NuGet Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter.

Remarque

Pour obtenir des conseils sur l'ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Exécutez AddQuickGridEntityFrameworkAdapter sur la collection de services dans le fichier Program pour enregistrer une implémentation IAsyncQueryExecutor compatible avec EF :

builder.Services.AddQuickGridEntityFrameworkAdapter();

L'exemple suivant utilise une ExampleTableDbSet<TEntity> (table) d'un contexte de base de données AppDbContext (context) comme source de données pour un composant QuickGrid :

@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();
}

Dans le bloc de code (@code) de l'exemple précédent :

  • Le champ context contient le contexte de la base de données, saisi sous la forme d'un AppDbContext.
  • La méthode de cycle de vie OnInitialized attribue un nouveau contexte de base de données (CreateDbContext) au champ context de la fabrique injectée (DbFactory).
  • La méthode asynchrone DisposeAsync élimine le contexte de la base de données lorsque le composant est éliminé.

Vous pouvez également utiliser n'importe quel opérateur LINQ pris en charge par EF pour filtrer les données avant de les transmettre au paramètre Items.

L'exemple suivant filtre les films en fonction du titre saisi dans une boîte de recherche. Le contexte de la base de données est BlazorWebAppMoviesContext, et le modèle est Movie. La propriété Title du film est utilisée pour l'opération de filtrage.

@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();
}

Pour un exemple pratique, consultez les ressources suivantes :

Prise en charge des noms d'affichage

Un titre de colonne peut être attribué en utilisant ColumnBase<TGridItem>.Title dans la balise PropertyColumn<TGridItem,TProp>. Dans l'exemple de film suivant, la colonne porte le nom « Release Date » pour les données relatives à la date de sortie du film :

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

Toutefois, la gestion des titres (noms) des colonnes à partir des propriétés du modèle lié est généralement un meilleur choix pour la gestion d'une application. Un modèle peut contrôler le nom d'affichage d'une propriété avec l'attribut [Display]. Dans l'exemple suivant, le modèle spécifie un nom d'affichage pour la date de sortie d'un film comme « Release Date » pour sa propriété ReleaseDate.

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

Pour permettre au composant QuickGrid d’utiliser la propriété DisplayAttribute.Name, sous-classe PropertyColumn<TGridItem,TProp>, dans le composant ou dans une classe distincte. Appelez la méthode GetName pour retourner la valeur de DisplayAttribute.Name localisée si un DisplayName non localisé ([DisplayName] attribut) ne contient pas la valeur :

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();
    }
}

Utilisez la sous-classe dans le composant QuickGrid Dans l'exemple suivant, c'est le DisplayNameColumn qui est utilisé. Le nom « Release Date » est fourni par l'attribut [Display] du modèle, il n'est donc pas nécessaire de spécifier un Title :

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

L'attribut [DisplayName] est également pris en charge :

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

Cependant, l'attribut [Display] est recommandé car il permet d'accéder à des propriétés supplémentaires. Par exemple, l'attribut [Display] offre la possibilité d'attribuer un type de ressource pour la localisation.

Données distantes

Dans les applications Blazor WebAssembly, la récupération de données d'une API Web basée sur JSON sur un serveur est une exigence courante. Pour récupérer uniquement les données nécessaires à la page/portée de visualisation actuelle et appliquer des règles de tri ou de filtrage sur le serveur, utilisez le paramètre ItemsProvider.

ItemsProvider peut également être utilisé dans une application Blazor côté serveur si l'application doit interroger un point de terminaison externe ou dans d'autres cas où les exigences ne sont pas couvertes par un IQueryable.

Fournissez un rappel correspondant au type de délégué GridItemsProvider<TGridItem>, où TGridItem est le type de données affichées dans la grille. Le callback reçoit un paramètre de type GridItemsProviderRequest<TGridItem>, qui spécifie l'index de départ, le nombre maximal de lignes et l'ordre de tri des données à renvoyer. En plus de renvoyer les éléments correspondants, un nombre total d'éléments (totalItemCount) est également nécessaire pour que la pagination et la virtualisation fonctionnent correctement.

L'exemple suivant permet d'obtenir des données de la base de données publique OpenFDA Food Enforcement.

Le paramètre GridItemsProvider<TGridItem> convertit le GridItemsProviderRequest<TGridItem> en une interrogation de la base de données OpenFDA. Les paramètres de la requête sont traduits dans le format URL particulier pris en charge par l'API JSON externe. Il n'est possible d'effectuer un tri et un filtrage que par le biais d'un tri et d'un filtrage pris en charge par l'API externe. Le point de terminaison OpenFDA ne prend pas en charge le tri, de sorte qu'aucune des colonnes n'est marquée comme pouvant être triée. Cependant, il permet de sauter des enregistrements (paramètre skip) et de limiter le retour des enregistrements (paramètre limit), de sorte que le composant peut activer la virtualisation et faire défiler rapidement des dizaines de milliers d'enregistrements.

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 },
            });

            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;
    }
}

Pour plus d'informations sur l'appel d'API Web, consultez la section Appeler une API Web à partir d'une applicationBlazor ASP.NET Core.

échafaudeur QuickGrid

L'échafaudage QuickGrid met en place des composants Razor avec QuickGrid pour afficher des données provenant d'une base de données.

Le scaffolder génère des pages CRUD (Create, Read, Update, and Delete) de base basées sur un modèle de données Entity Framework Core. Vous pouvez échafauder des pages individuelles ou toutes les pages CRUD. Vous sélectionnez la classe de modèle et le DbContext, en créant éventuellement un nouveau DbContext si nécessaire.

Les composants Razor échafaudés sont ajoutés au projet dans un dossier généré nommé d'après la classe de modèle. Le composant Index généré utilise un composant QuickGrid pour afficher les données. Personnalisez les composants générés selon vos besoins et activez l'interactivité pour tirer parti des fonctionnalités interactives, telles que la pagination, le tri et le filtrage.

Les composants produits par le scaffolder nécessitent un rendu côté serveur (SSR), ils ne sont donc pas pris en charge lorsqu'ils sont exécutés sur WebAssembly.

Cliquez avec le bouton droit de la souris sur le dossier Components/Pages et sélectionnez Ajouter>Nouvel élément échafaudé

La boîte de dialogue Ajouter un nouvel élément d'échafaudage étant ouverte sur le composant Installé>Communs>Blazor>Razor, sélectionnez RazorComponents using Entity Framework (CRUD). Cliquez sur le bouton Ajouter.

CRUD est un acronyme pour Create, Read, Update, and Delete (créer, lire, mettre à jour et supprimer). L'échafaudage produit des composants de création, d'édition, de suppression, de détails et d'index pour l'application.

Complétez la boîte de dialogue Ajout de Razor Components en utilisant Entity Framework (CRUD) :

  • La liste déroulante Modèle comprend d'autres modèles permettant de créer spécifiquement des composants de création, d'édition, de suppression, de détail et de liste. Cette liste déroulante est utile lorsque vous devez créer un type de composant spécifique lié à une classe de modèle. Laissez la liste déroulante Modèle réglée sur CRUD pour échafauder un ensemble complet de composants.
  • Dans la liste déroulante Classe de modèle, sélectionnez la classe de modèle. Un dossier est créé pour les composants générés à partir du nom du modèle (si la classe de modèle est nommée Movie, le dossier est automatiquement nommé MoviePages).
  • Pour la classe DbContext, adoptez l’une des approches suivantes :
    • Sélectionnez une classe DbContext existante dont vous savez qu'elle possède une inscription de fournisseur de fabrique (AddDbContextFactory).
    • Sélectionnez le bouton + (signe plus) et utilisez la boîte de dialogue modale Ajouter un contexte de données pour fournir un nouveau nom de classe DbContext, qui inscrit la classe auprès d'un fournisseur de fabrique au lieu d'utiliser le type de contexte directement en tant qu'inscription de service.
  • Après la fermeture de la boîte de dialogue du modèle, la liste déroulante fournisseur de base de données indique par défaut SQL Server. Vous pouvez sélectionner le fournisseur approprié pour la base de données que vous utilisez. Les options comprennent SQL Server, SQLite, PostgreSQL et Azure Cosmos DB.
  • Sélectionnez Ajouter.

Pour un exemple d'utilisation de l'échafaudage QuickGrid, voir Construire une application de base de données de films Blazor (Vue d'ensemble).

Plusieurs requêtes de EF Core simultanées déclenchent System.InvalidOperationException

Plusieurs requêtes de EF Core simultanées peuvent déclencher les System.InvalidOperationExceptionsuivantes :

System.InvalidOperationException : une deuxième opération a été démarrée sur cette instance de contexte avant la fin d’une opération précédente. Cela est généralement dû à des threads différents utilisant concurrentément la même instance de DbContext. Pour plus d’informations sur la façon d’éviter les problèmes de threading avec DbContext, consultez https://go.microsoft.com/fwlink/?linkid=2097913.

Ce scénario est planifié pour une amélioration dans une prochaine version de ASP.NET Core. Pour plus d’informations, consultez [Blazor] Améliorer l’expérience avec QuickGrid et EF Core (dotnet/aspnetcore #58716).

En attendant, vous pouvez traiter le problème avec un ItemsProvider et un jeton d’annulation. Le jeton d’annulation empêche les requêtes simultanées en annulant la demande précédente lorsqu’une nouvelle demande est émise.

Prenons l’exemple suivant, qui est basé sur le composant de base de données vidéo Index pour le didacticiel Générer une application de base de données de films Blazor (Vue d’ensemble). La version plus simple intégrée dans l’application peut être vue dans l’exemple d’application de l’article. Le composant Index intégré dans l’application est remplacé par le composant suivant.

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;
    }
}