Showing posts with label QuickGrid. Show all posts
Showing posts with label QuickGrid. Show all posts

Monday, February 16, 2026

Scaffolding Blazor pages with microsoft.dotnet-scaffold

In this tutorial, I will show you how to build a server-side Blazor application that connects directly to a SQLite database using Entity Framework Core. We will scaffold the CRUD pages with the microsoft.dotnet-scaffold tool. There is also a quick introduction into the QuickGrid component.

Source Code: https://github.com/medhatelmasry/BlazorStudents

Companion Video: https://youtu.be/4hbE-GZ-WZA

Pre-requisites

  1. .NET Framework 10+
  2. VS Code (or any other .NET editor)
  3. dotnet-ef tool
  4. microsoft.dotnet-scaffold tool

Getting Started

In a terminal window, go to your working directory. Enter the following commands to create a Server-Side Blazor application inside a directory called BlazorStudents:

dotnet new blazor -int server --auth individual -o BlazorStudents
cd BlazorStudents

Run the application by entering the following command:

dotnet watch

The following page will load into your default browser:

The default page after creating and running a server-side blazor template.

Open the BlazorStudents folder in Visual Studio Code (or any other .NET editor).

We will work with a very simple student model. Therefore, add a Student class file in a folder named Models with the following content: 

public class Student {
    public int StudentId { get; set; }

    [Required(ErrorMessage = "You must enter first name.")]
    public string? FirstName { get; set; }

    [Required(ErrorMessage = "You must enter last name.")]
    public string? LastName { get; set; }

    [Required(ErrorMessage = "You must enter school.")]
    public string? School { get; set; }
    
    [Required(ErrorMessage = "You must enter gender.")]
    public string? Gender { get; set; }
    
    [Required(ErrorMessage = "You must enter date of birth.")]
    public DateTime? DateOfBirth { get; set; }
}

From within a terminal window at the root of your BlazorStudents project,  run the following command to add some required packages:

dotnet add package CsvHelper

The CsvHelper package will help us read data from a CSV.

Developers prefer having sample data when building data driven applications. Therefore, we will create some sample data to ensure that our application behaves as expected. Copy the CSV data at https://gist.github.com/medhatelmasry/e8d4edc2772a538419adda45e8f82685 and save it in a text file named students.csv in the wwwroot folder.

Edit Data/ApplicationDbContext.cs and add to the class the following property and methods:

public DbSet<Student> Students => Set<Student>();

protected override void OnModelCreating(ModelBuilder modelBuilder) {
  base.OnModelCreating(modelBuilder);
  modelBuilder.Entity<Student>().HasData(GetStudents());
}

private static IEnumerable<Student> GetStudents() {
  string[] p = { Directory.GetCurrentDirectory(), "wwwroot", "students.csv" };
  var csvFilePath = Path.Combine(p);

  var config = new CsvConfiguration(CultureInfo.InvariantCulture) {
    PrepareHeaderForMatch = args => args.Header.ToLower(),
  };

  var data = new List<Student>().AsEnumerable();
  using (var reader = new StreamReader(csvFilePath)) {
    using (var csvReader = new CsvReader(reader, config)) {
      data = csvReader.GetRecords<Student>().ToList();
    }
  }

  return data;
}

Notice the above code is adding contents of the wwwroot/students.csv file as seed data into the database.

We are now ready to apply Entity Framework migrations, create the database and seed data. If you have not done so already, you will need to globally install the Entity Framework CLI tool. This tool is installed globally on your computer by running the following command in a terminal window:

dotnet tool install --global dotnet-ef

To have a clean start with Entity Framework migrations, delete the Data/Migrations folder and the Data/app.db files.

From within a terminal window inside the BlazorStudents root directory, run the following command to create migrations:

dotnet ef migrations add Stu -o Data/Migrations

This results in the creation of a migration file ending with the name ....Stu.cs in the Data/Migrations folder. 

The next step is to create the SQLite Data/app.db database file. This is done by adding the following code to Program.cs, right before app.Run():

using (var scope = app.Services.CreateScope()) {
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<ApplicationDbContext>();    
    context.Database.Migrate();
}

Run the application. This will cause students data to be seeded in the database.

Scaffolding Blazor Components

If you have not done so already, install the dotnet scaffold tool with this terminal window command:

dotnet tool install -g microsoft.dotnet-scaffold

Let us scaffold the CRUD pages for students. Run the scaffold tool from the root directory of your application with this command:

dotnet scaffold

Follow these steps....

After running the "dotnet scaffold" tool, when asked to pick a scaffolding category, select "blazor".

When asked to pick a scaffolding command, choose "Razor Components with EntityFrameworkCore (dotnet-scaffold)".

When asked for a .NET prject file, choose the only one available: BlazorStudents.csproj.

When asked for model name, choose Student (Student).

When asked for database context class, enter ApplicationDbContext.

When asked for database provider, choose: sqlite-efcore (sqlite-efcore).

When asked for page type, choose: CRUD (CRUD).

When asked to include prerelease packages, answer no.

The scaffolding process adds the following pages to your application:

There is a new folder named StudentPages (under Components/Pages) with all the razor components for CRUD operations.

Edit Components/Layout/NavMenu.razor to add this menu item:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="students">
        <span class="bi bi-lock-nav-menu" aria-hidden="true"></span> Students
    </NavLink>
</div>

Find the following code in Program.cs and delete it because the scaffold tool registered ApplicatioDbContext using DbContextFactory:

builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(connectionString));

Run the application with:

dotnet watch

The app will launch in your default browser.

After the web app launches in your default browser, click on students in the left navigation. A list of students will display in the main panel

You should have the full CRUD experience once you click on Students in the left navigation.

QuickGrid

If you open StudentPages/Index.razor in your editor, you will notice that the QuickGrid Blazor component is being used to display students data. This is the code that uses QuickGrid:

<QuickGrid Class="table" Items="context.Students">
  <PropertyColumn Property="student => student.FirstName" />
  <PropertyColumn Property="student => student.LastName" />
  <PropertyColumn Property="student => student.School" />
  <PropertyColumn Property="student => student.DateOfBirth" />

  <TemplateColumn Context="student">
    <a href="@($"students/edit?studentid={student.StudentId}")">Edit</a> |
    <a href="@($"students/details?studentid={student.StudentId}")">Details</a> |
    <a href="@($"students/delete?studentid={student.StudentId}")">Delete</a>
  </TemplateColumn>
</QuickGrid>

Visit the QuickGrid for Blazor site for more information on this freely available component.

Pagination

Let's extend the QuickGrid component to add paging to StudentPages/Index.razor. Add this directive right under the first line (@page "/students"):

@rendermode InteractiveServer

The above directive tells Blazor that a component should be rendered on the server and made fully interactive using the Blazor Server model.

Add this instance variable to the @code { .... } block

private PaginationState pagination = new PaginationState { ItemsPerPage = 10 };

Next, Add the following attribute to the opening <QuickGrid .... > tag:

Pagination="@pagination"

Finally, place this Paginator component right after the closing </QuickGrid> tag:

<Paginator State="@pagination" />

Refreah the Students List page. You will see pagination in action.

Sorting

Making the columns sortable involves just adding an attribute to the <PropertyColumn...> opening tags for FirstName, LastName, School, and DateOfBirth as follows:

<PropertyColumn Property="student => student.FirstName" Sortable="true" />
<PropertyColumn Property="student => student.LastName" Sortable="true" />
<PropertyColumn Property="student => student.School" Sortable="true" />
<PropertyColumn Property="student => student.DateOfBirth" Sortable="true" />

You can now click on the column titles to sort the columns as needed:

Filtering

Add this filter input field right above the <Quickgrid ...> opening tag:

<p>There are @filtered.Count() students.</p>

<div class="search-box">
    <input class="form-control me-sm-2 " style="width: 95%" type="search" autofocus @bind="itemsFilter"
           @bind:event="oninput" placeholder="Search Filter ..." />
</div>

Add these C# properties inside the @code { . . .  } block:

string? itemsFilter;

private List<Student>? studentList {
  get {
    var data = context.Students!.ToList();
    if (!data.Any()) {
      return null;
    } else {

      return data;
    }
  }
}

private IQueryable<Student> filtered {
  get {
    if (studentList == null || !studentList.Any()) {
      return Enumerable.Empty<Student>().AsQueryable();
    }

    if (string.IsNullOrEmpty(itemsFilter)) {
      return studentList!.AsQueryable();
    } else {
      var filteredList = studentList!.AsQueryable()
      .Where(
      b => b.FirstName!.Contains(itemsFilter, StringComparison.CurrentCultureIgnoreCase)
      || b.LastName!.Contains(itemsFilter, StringComparison.CurrentCultureIgnoreCase)
      || b.School!.Contains(itemsFilter, StringComparison.CurrentCultureIgnoreCase)
      || b.Gender!.Contains(itemsFilter, StringComparison.CurrentCultureIgnoreCase)
      || b.DateOfBirth.ToString()!.Contains(itemsFilter, StringComparison.CurrentCultureIgnoreCase)
      );
      return filteredList;
    }
  }
}

In the opening <QuickGrid ... > tag, change the value of the Items attribure from "context.Students" to simply:

@filtered

You can now filter any text in any of the columns as shown below:

If you enter 1998 in the filter, all those born in 1998 will display in the main panel.

Component CSS

With Blazor components, it is easy create CSS that targets individual components. Simply create a file with the same name as the component and add to it .css. 

For example:

Create a file named StudentPages/Index.razor.css in the same folder as the component itself with this styling:

p.create-new {
    background-color: orange;
}

In StudentPages/Index.razor component, add the following styling to the <p> tag that contains the “Create New” link as follows:

<p class="create-new">
    <a href="students/create">Create New</a>
</p>

You will notice that styling is successfully applied to the StudentPages/Index.razor component.

Image showing that the styling in StudentPages/Index.razor.css has affected the Index.razor component by setting the background color of the "Create New" link to orange.

The .NET scaffold tool can be used for more than creating pages for Blazor app. Among other things, it can be used for scaffolding Aspire, API, MVC Controllerts, and Itentity.

Monday, December 11, 2023

Mix Blazor with ASP.NET Core MVC

In this tutorial I will show you how you can inject Blazor components into your regular ASP.NET Core MVC web application. We will integrate the free QuickGrid Blazor components into our MVC application. 

Source code: https://github.com/medhatelmasry/MvcWithBlazor

Companion video: https://youtu.be/dsoGW59Vtpk

Prerequisites

It is assumed that you have installed the following on your computer:
  • .NET 8.0
  • Visual Studio Code editor

Getting Started

In a suitable working directory, create an ASP.NET MVC 8.0 web application with the following terminal window command:

dotnet new mvc -f net8.0 --name MvcWithBlazor

Change into the new directory with:

cd MvcWithBlazor

Add the following Blazor QuickGrid package with this terminal window command:

dotnet add package Microsoft.AspNetCore.Components.QuickGrid -v 8.0.0

Start Visual Studio Code with:

code .

To keep it simple, we will create some hard-coded student data. Create a Student.cs class file inside the Models folder with the following code:

namespace MvcWithBlazor.Models;
public class Student
{
    required public int? Id { get; set; }
    required public string FirstName { get; set; }
    required public string LastName { get; set; }
    required public string School { get; set; }
    public static IQueryable<Student> GetStudents()
    {
        int ndx = 0;
        List<Student> students = new List<Student>() {
            new Student() { Id = ++ndx, FirstName="Max", LastName="Pao", School="Science" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Fay", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Ann", LastName="Sun", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Joe", LastName="Fox", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Sue", LastName="Mai", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Ben", LastName="Lau", School="Business" },
            new Student() { Id = ++ndx, FirstName="Zoe", LastName="Ray", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Sam", LastName="Ash", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Dan", LastName="Lee", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Pat", LastName="Day", School="Science" },
            new Student() { Id = ++ndx, FirstName="Kim", LastName="Rex", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Tim", LastName="Ram", School="Business" },
            new Student() { Id = ++ndx, FirstName="Rob", LastName="Wei", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Jan", LastName="Tex", School="Science" },
            new Student() { Id = ++ndx, FirstName="Jim", LastName="Kid", School="Business" },
            new Student() { Id = ++ndx, FirstName="Ben", LastName="Chu", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Mia", LastName="Tao", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Ted", LastName="Day", School="Business" },
            new Student() { Id = ++ndx, FirstName="Amy", LastName="Roy", School="Science" },
            new Student() { Id = ++ndx, FirstName="Ian", LastName="Kit", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Liz", LastName="Tan", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Mat", LastName="Roy", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Deb", LastName="Luo", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Ana", LastName="Poe", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Lyn", LastName="Raj", School="Science" },
            new Student() { Id = ++ndx, FirstName="Amy", LastName="Ash", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Kim", LastName="Kid", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Bec", LastName="Fry", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Eva", LastName="Lap", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Eli", LastName="Yim", School="Business" },
            new Student() { Id = ++ndx, FirstName="Sam", LastName="Hui", School="Science" },
            new Student() { Id = ++ndx, FirstName="Joe", LastName="Jin", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Liz", LastName="Kuo", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Ric", LastName="Mak", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Pam", LastName="Day", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Stu", LastName="Gad", School="Business" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Bee", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Bob", LastName="Lam", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Jim", LastName="Ots", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Mag", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Hal", LastName="Doe", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Roy", LastName="Kim", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Vis", LastName="Cox", School="Science" },
            new Student() { Id = ++ndx, FirstName="Kay", LastName="Aga", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Reo", LastName="Hui", School="Business" },
            new Student() { Id = ++ndx, FirstName="Bob", LastName="Roe", School="Medicine" },
        };
        return students.AsQueryable();
    }
}

Create a Components folder and add to it the following files with their respective contents:

_Imports.razor

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using MvcWithBlazor
@using MvcWithBlazor.Components 
@using Microsoft.AspNetCore.Components.QuickGrid
@using MvcWithBlazor.Models

Routes.razor

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>

App.razor

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="MvcWithBlazor.styles.css" />
    <HeadOutlet />
</head>
<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>
</html>

Note that you need adjust the above highlighted text with your application name.

Inside the Components folder, add a sub-folder named Pages. Inside the Components/Pages folder add a Students.razor component file with this code:

@page "/students"
@rendermode InteractiveServer
<PageTitle>Students</PageTitle>
<h1>Students</h1>
<QuickGrid Items="@students" Pagination="@pagination">
    <PropertyColumn Property="@(_ => _.Id)" Sortable="true" />
    <TemplateColumn Title="Name" SortBy="@sortByName">
        <div class="flex items-center">
            <nobr>
                <strong>@context.FirstName @context.LastName</strong>
            </nobr>
        </div>
    </TemplateColumn>
    <PropertyColumn Property="@(_ => _.School)" Sortable="true" />
</QuickGrid>
<Paginator State="@pagination" />

@code {
    IQueryable<Student> students = Student.GetStudents();
    PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
    GridSort<Student> sortByName = GridSort<Student>
    .ByAscending(_ => _.FirstName).ThenAscending(_ => _.LastName);
}

Adding appropriate services and middleware to Program.cs

Add the following using statement at the top of Program.cs:

using MvcWithBlazor.Components;

Add the following razor component services before the line that calls builder.Build():

builder.Services
.AddRazorComponents()
.AddInteractiveServerComponents()
.AddCircuitOptions(options => options.DetailedErrors = true); // for debugging razor components

Add this anti-forgery middleware right after 'app.UseRouting();':

app.UseAntiforgery();

Place this code before the line that calls app.Run():

app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();

Try it out

Run the application with the following terminal window command:

dotnet watch

When the home page loads in your browser, try the /students page. You should see a page that looks like this:


You can sort any column by clicking on the column title and the paging should also work. We have succeeded in mixing Blazor with ASP.NET MVC. 

Injecting Blazor components into MVC views

We can inject Blazor components directly into MVC .cshtml views. We must first make the appropriate namespaces visible to the environment for the MVC views. Add the following using statements to Views/_ViewImports.cshtml:

@using MvcWithBlazor.Components
@using MvcWithBlazor.Components.Pages

Note that you must adjust the above highlighted text with the appropriate name of your application.

Add the following <base> tag and Component Tag Helper for a HeadOutlet component to the <head> markup of Views/Shared/_Layout.cshtml:

<base href="~/" />
<component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" 
    render-mode="ServerPrerendered" />

The HeadOutlet component is used to render head (<head>) content for page titles (PageTitle component) and other head elements (HeadContent component) set by Razor components.

Also, in the same Views/Shared/_Layout.cshtml file, add a <script> tag for the blazor.web.js script immediately before the Scripts render section (@await RenderSectionAsync(...)):

<script src="_framework/blazor.web.js"></script>

Next, add the following tag to the bottom of home page Views/Home/Index.cshtml:

<component type="typeof(Students)" render-mode="ServerPrerendered" />

Point your browser to the home page of the ASP.NET Core MVC app. You should experience a page that has the Students component embedded inside it.

Paging and sorting work as expected.

Conclusion

You can do the same with ASP.NET Core Razor Pages.

I hope you found this article useful.

Wednesday, December 6, 2023

Using free QuickGrid component with Static Server Rendering Blazor App

 Overview

QuickGrid is a Razor component that quickly and efficiently displays data in tabular form. Visit https://aspnet.github.io/quickgridsamples/ to check out what you can do with this component. In this tutorial, you will discover how easy it is to incorporate in your apps and how versatile it is. I will be using the current version of .NET 8.0.

Source Code: https://github.com/medhatelmasry/BlazorQuickGrid

Companion Video: https://youtu.be/LBoG1WMaFGI

Getting Started

We will create a Static Server rendering (SSR) application with the following terminal command:

dotnet new blazor --name BlazorQuickGrid 

cd BlazorQuickGrid

Add this class to Models/Student.cs to generate some sample student data:

namespace BlazorQuickGrid.Models;

public class Student {
    required public int? Id { get; set; }
    required public string FirstName { get; set; }
    required public string LastName { get; set; }
    required public string School { get; set; }

    public static IQueryable<Student> GetStudents() {
        int ndx = 0;
        List<Student> students = new List<Student>() {
            new Student() { Id = ++ndx, FirstName="Max", LastName="Pao", School="Science" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Fay", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Ann", LastName="Sun", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Joe", LastName="Fox", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Sue", LastName="Mai", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Ben", LastName="Lau", School="Business" },
            new Student() { Id = ++ndx, FirstName="Zoe", LastName="Ray", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Sam", LastName="Ash", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Dan", LastName="Lee", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Pat", LastName="Day", School="Science" },
            new Student() { Id = ++ndx, FirstName="Kim", LastName="Rex", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Tim", LastName="Ram", School="Business" },
            new Student() { Id = ++ndx, FirstName="Rob", LastName="Wei", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Jan", LastName="Tex", School="Science" },
            new Student() { Id = ++ndx, FirstName="Jim", LastName="Kid", School="Business" },
            new Student() { Id = ++ndx, FirstName="Ben", LastName="Chu", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Mia", LastName="Tao", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Ted", LastName="Day", School="Business" },
            new Student() { Id = ++ndx, FirstName="Amy", LastName="Roy", School="Science" },
            new Student() { Id = ++ndx, FirstName="Ian", LastName="Kit", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Liz", LastName="Tan", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Mat", LastName="Roy", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Deb", LastName="Luo", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Ana", LastName="Poe", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Lyn", LastName="Raj", School="Science" },
            new Student() { Id = ++ndx, FirstName="Amy", LastName="Ash", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Kim", LastName="Kid", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Bec", LastName="Fry", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Eva", LastName="Lap", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Eli", LastName="Yim", School="Business" },
            new Student() { Id = ++ndx, FirstName="Sam", LastName="Hui", School="Science" },
            new Student() { Id = ++ndx, FirstName="Joe", LastName="Jin", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Liz", LastName="Kuo", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Ric", LastName="Mak", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Pam", LastName="Day", School="Computing" },
            new Student() { Id = ++ndx, FirstName="Stu", LastName="Gad", School="Business" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Bee", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Bob", LastName="Lam", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Jim", LastName="Ots", School="Medicine" },
            new Student() { Id = ++ndx, FirstName="Tom", LastName="Mag", School="Mining" },
            new Student() { Id = ++ndx, FirstName="Hal", LastName="Doe", School="Agriculture" },
            new Student() { Id = ++ndx, FirstName="Roy", LastName="Kim", School="Nursing" },
            new Student() { Id = ++ndx, FirstName="Vis", LastName="Cox", School="Science" },
            new Student() { Id = ++ndx, FirstName="Kay", LastName="Aga", School="Tourism" },
            new Student() { Id = ++ndx, FirstName="Reo", LastName="Hui", School="Business" },
            new Student() { Id = ++ndx, FirstName="Bob", LastName="Roe", School="Medicine" },
        };
        return students.AsQueryable();
    }
}

Add this QuickGrid package to your server-side blazor app:

dotnet add package Microsoft.AspNetCore.Components.QuickGrid

Add this to Components/_Imports.razor:

@using Microsoft.AspNetCore.Components.QuickGrid
@using BlazorQuickGrid.Models

Replace Components/Pages/Home.razor with the following:

@page "/"
@rendermode InteractiveServer

<PageTitle>Students</PageTitle>
<h1>Students</h1>
<QuickGrid Items="@students">
    <PropertyColumn Property="@(_ => _.Id)" Sortable="true" />
    <PropertyColumn Property="@(_ => _.FirstName)" Sortable="true" />
    <PropertyColumn Property="@(_ => _.LastName)" Sortable="true" />
    <PropertyColumn Property="@(_ => _.School)" Sortable="true" />
</QuickGrid>
@code {
    IQueryable<Student> students = Student.GetStudents();
}

You can now run your app with:

dotnet watch

The following page would load in your browser:


One of the quick wins that you get out of the box is the ability to sort. Click on the column titles and you will see that the data in the column sorts.

Pagination

Add this variable inside the @code { . . .  } block in Components/Pages/Home.razor.

private PaginationState pagination = new PaginationState { ItemsPerPage = 10 };

Add this parameter in to the opening <QuickGrid> tag:

Pagination="@pagination"

To provide for paging, add this pagination component under </QuickGrid>:

<Paginator State="@pagination" />

Pagination will appear at the bottom of the table:


TemplateColumn

Suppose we want to combine first and last names into the same column. This is a good example of why you would use TemplateColumn. 

Replace:

<PropertyColumn Property="@(_ => _.FirstName)" Sortable="true" />
<PropertyColumn Property="@(_ => _.LastName)" Sortable="true" />

WITH

<TemplateColumn Title="Name">
  <div class="flex items-center">
    <nobr>
      @context.FirstName @context.LastName
    </nobr>
  </div>
</TemplateColumn>


Although we succeeded in putting the full name under one column, unfortunately, the Name column is not sortable. Let us fix that.Add this sortByName variable into the @code {  . . . } code block:

GridSort<Student> sortByName = GridSort<Student>
    .ByAscending(_ => _.FirstName).ThenAscending(_ => _.LastName);

Also, add this parameter to the opening <TemplateColumn> tag for Name:

SortBy="@sortByName"
It is now possible to sort the Name column.

There is much more you can do with the QuickGrid component. Consider this a small taste of what is possible.