Example T1155154
Visible to All Users

Grid for Blazor - How to bind the component to an Instant Feedback data source and enable edit operations

This example demonstrates how to use the Entity Framework Core data access technology to bind the DevExpress Blazor Grid component to an Instant Feedback data source. In the example, you can add, edit, and delete data rows in the Grid component. The Grid validates input data and displays error messages.

Bind the Grid to an Instant Feedback Data Source

Overview

Instant Feedback data sources are designed to work with large data collections. They load data in small portions on demand in background threads and do not freeze the Grid UI. Instant Feedback data sources help you to reduce memory consumption but impose multiple limitations. Refer to the following topic for more information: Server Mode Sources - Common Specifics and Limitations.

Bind the Grid to an Instant Feedback Data Source

Follow the steps below to use the Entity Framework Core technology to bind the Grid component to an Instant Feedback data source:

  1. Add the following NuGet packages to your project:
  2. Create a model for your database and register the database context.
  3. Register a DbContext factory in the Program.cs file.
  4. Add references to the model, data source, and data access technology namespaces to the page that displays the Grid component. Use the @inject Razor directive to inject the DbContext factory service into the component:
    Razor
    @using InstantFeedback.Models; @using Microsoft.EntityFrameworkCore @using DevExpress.Data.Linq @inject IDbContextFactory<NorthwindContext> NorthwindContextFactory
  5. Create an instance of the EntityInstantFeedbackSource class, specify its parameters, and bind it to the Grid's Data property:
    Razor
    <DxGrid Data="InstantFeedbackSource"> <!-- ... --> </DxGrid> @code { EntityInstantFeedbackSource InstantFeedbackSource { get; set; } NorthwindContext Northwind { get; set; } protected override void OnInitialized() { Northwind = NorthwindContextFactory.CreateDbContext(); InstantFeedbackSource = new EntityInstantFeedbackSource(e => { e.KeyExpression = "OrderId"; e.QueryableSource = Northwind.Orders; }); } }
  6. Implement the IDisposable interface and dispose of the data source instance and context in the page's Dispose method:
    Razor
    @implements IDisposable // ... @code { //... public void Dispose() { InstantFeedbackSource?.Dispose(); Northwind?.Dispose(); } }

Enable Edit Operations

The Grid component supports multiple edit modes. Follow the steps below to allow users to edit grid data in edit form mode:

  1. Declare a DxGridCommandColumn object in the Grid's Columns template. This column displays the predefined New, Edit, and Delete command buttons.
  2. Use the EditFormTemplate property to define edit form content.
  3. The EditModelSaving event occurs after a user submits the edit form and validation is passed. Use the EditModel event argument to access the edit model that stores all changes. Copy the values of all edit model fields that can be changed to the corresponding fields of the DataItem event argument, then save changes to the bound data source. To assign all edit model field values to the data item fields simultaneously, you can call the AutoMapper library's Map method.
  4. The DataItemDeleting event occurs once a user confirms the delete operation in the delete confirmation dialog. In the event handler, check user input and access permissions and post changes to the data source.
  5. If your data object has a primary key, assign it to the KeyFieldName or KeyFieldNames property. If you do not specify these properties, the Grid uses standard .NET value equality comparison to identify data items.

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

Pages/Index.razor
Razor
@page "/" @using AutoMapper @using InstantFeedback.Models; @using Microsoft.EntityFrameworkCore @using DevExpress.Data.Linq @inject IDbContextFactory<NorthwindContext> NorthwindContextFactory @implements IDisposable <DxGrid Data="InstantFeedbackSource" EditModelSaving="OnEditModelSaving" DataItemDeleting="OnDataItemDeleting" KeyFieldName="OrderId"> <Columns> <DxGridCommandColumn /> <DxGridDataColumn FieldName="ShipName" /> <DxGridDataColumn FieldName="ShipCity" /> <DxGridDataColumn FieldName="ShipCountry" /> <DxGridDataColumn FieldName="Freight" /> <DxGridDataColumn FieldName="OrderDate" /> <DxGridDataColumn FieldName="ShippedDate" /> </Columns> <EditFormTemplate Context="editFormContext"> <DxFormLayout> <DxFormLayoutItem Caption="Ship Name:"> @editFormContext.GetEditor("ShipName") </DxFormLayoutItem> <DxFormLayoutItem Caption="Ship City:"> @editFormContext.GetEditor("ShipCity") </DxFormLayoutItem> <DxFormLayoutItem Caption="Ship Country:"> @editFormContext.GetEditor("ShipCountry") </DxFormLayoutItem> <DxFormLayoutItem Caption="Freight:"> @editFormContext.GetEditor("Freight") </DxFormLayoutItem> <DxFormLayoutItem Caption="Order Date:"> @editFormContext.GetEditor("OrderDate") </DxFormLayoutItem> <DxFormLayoutItem Caption="Shipped Date:"> @editFormContext.GetEditor("ShippedDate") </DxFormLayoutItem> </DxFormLayout> </EditFormTemplate> </DxGrid> @code { EntityInstantFeedbackSource InstantFeedbackSource { get; set; } NorthwindContext Northwind { get; set; } IMapper ProductMapper { get; set; } protected override void OnInitialized() { Northwind = NorthwindContextFactory.CreateDbContext(); InstantFeedbackSource = new EntityInstantFeedbackSource(e => { e.KeyExpression = "OrderId"; e.QueryableSource = Northwind.Orders; }); var config = new MapperConfiguration(c => c.CreateMap<Order, Order>()); ProductMapper = config.CreateMapper(); } async Task OnEditModelSaving(GridEditModelSavingEventArgs e) { var editModel = (Order)e.EditModel; // Re-query a data item from the database. var dataItem = e.IsNew ? new Order() : Northwind.Orders.Find(editModel.OrderId); // Assign changes from the edit model to the data item. if (dataItem != null) { ProductMapper.Map<Order, Order>(editModel, dataItem); // Post changes to the database. if (e.IsNew) await Northwind.AddAsync(dataItem); await Northwind.SaveChangesAsync(); } } async Task OnDataItemDeleting(GridDataItemDeletingEventArgs e) { // Re-query a data item from the database. var orderId = e.Grid.GetDataItemValue(e.DataItem, "OrderId"); var dataItem = Northwind.Orders.Find(orderId); if (dataItem != null) { // Remove the data item from the database. Northwind.Remove(dataItem); await Northwind.SaveChangesAsync(); } } public void Dispose() { InstantFeedbackSource?.Dispose(); Northwind?.Dispose(); } }
Program.cs
C#
using InstantFeedback.Models; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddDevExpressBlazor(options => { options.BootstrapVersion = DevExpress.Blazor.BootstrapVersion.v5; options.SizeMode = DevExpress.Blazor.SizeMode.Medium; }); builder.Services.AddDbContextFactory<NorthwindContext>((sp, options) => { var env = sp.GetRequiredService<IWebHostEnvironment>(); var dbPath = Path.Combine(env.ContentRootPath, "Northwind.db"); options.UseSqlite("Data Source=" + dbPath); }); builder.WebHost.UseWebRoot("wwwroot"); builder.WebHost.UseStaticWebAssets(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.Run();
Models/Invoice.cs
C#
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace InstantFeedback.Models { public partial class Order { public int OrderId { get; set; } [Required] public string ShipName { get; set; } [Required] public string ShipCity { get; set; } [Required] public string ShipCountry { get; set; } public decimal? Freight { get; set; } [Range(typeof(DateTime), "1/1/2010", "1/1/2024", ErrorMessage = "OrderDate must be between {1:d} and {2:d}")] public DateTime? OrderDate { get; set; } [Range(typeof(DateTime), "1/1/2010", "1/1/2024", ErrorMessage = "ShippedDate must be between {1:d} and {2:d}")] public DateTime? ShippedDate { get; set; } } }
Models/NorthwindContext.cs
C#
using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace InstantFeedback.Models; public partial class NorthwindContext : DbContext { public NorthwindContext() {} public NorthwindContext(DbContextOptions<NorthwindContext> options) : base(options) {} public virtual DbSet<Order> Orders { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS"); modelBuilder.Entity<Order>(entity => { entity.HasIndex(e => e.OrderDate, "OrderDate"); entity.HasIndex(e => e.ShippedDate, "ShippedDate"); entity.Property(e => e.OrderId).HasColumnName("OrderID"); entity.Property(e => e.Freight) .HasColumnType("money") .HasDefaultValueSql("((0))"); entity.Property(e => e.OrderDate).HasColumnType("datetime"); entity.Property(e => e.ShipCity).HasMaxLength(15); entity.Property(e => e.ShipCountry).HasMaxLength(15); entity.Property(e => e.ShipName).HasMaxLength(40); entity.Property(e => e.ShippedDate).HasColumnType("datetime"); }); OnModelCreatingPartial(modelBuilder); } partial void OnModelCreatingPartial(ModelBuilder modelBuilder); }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.