The DataGrid uses SfDataManager
, which supports both RESTful JSON data services binding and IEnumerable binding. The DataSource
value can be assigned either with the property values from SfDataManager
or list of business objects.
It supports the following kinds of data binding method:
When using
DataSource
asIEnumerable<T>
, component type(TValue) will be inferred from its value. When usingSfDataManager
for data binding then the TValue must be provided explicitly in the datagrid component.
To bind list binding to the datagrid, you can assign a IEnumerable object to the DataSource
property. The list data source can also be provided as an instance of the SfDataManager
or by usingSfDataManager
component.
@using Syncfusion.Blazor.Grids
<SfGrid DataSource="@Orders" AllowPaging="true">
<GridPageSettings PageSize="5"></GridPageSettings>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public List<Order> Orders { get; set; }
protected override void OnInitialized()
{
Orders = Enumerable.Range(1, 75).Select(x => new Order()
{
OrderID = 1000 + x,
CustomerID = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)],
Freight = 2.1 * x,
OrderDate = DateTime.Now.AddDays(-x),
}).ToList();
}
public class Order {
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
By default,
SfDataManager
uses BlazorAdaptor for list data-binding.
Grid is a generic component which is strongly bound to a model type. There are cases when the model type is unknown during compile type. In such cases you can bound data to the grid as list of ExpandoObject.
To know about ExpandoObject data binding in Blazor DataGrid component, you can check on this video.
ExpandoObject can be bound to datagrid by assigning to the DataSource
property. Grid can also perform all kind of supported data operations and editing in ExpandoObject.
@using Syncfusion.Blazor.Grids
@using System.Dynamic
<SfGrid DataSource="@Orders" AllowPaging="true" Toolbar="@ToolbarItems">
<GridEditSettings AllowAdding="true" AllowDeleting="true" AllowEditing="true"></GridEditSettings>
<GridColumns>
<GridColumn Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field="CustomerID" HeaderText="Customer Name" Width="120"></GridColumn>
<GridColumn Field="Freight" HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field="OrderDate" HeaderText=" Order Date" Format="d" TextAlign="TextAlign.Right" Width="130" Type="ColumnType.Date"></GridColumn>
<GridColumn Field="ShipCountry" HeaderText="Ship Country" EditType="EditType.DropDownEdit" Width="150"></GridColumn>
<GridColumn Field="Verified" HeaderText="Active" DisplayAsCheckBox="true" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code {
public List<ExpandoObject> Orders { get; set; } = new List<ExpandoObject>();
private List<string> ToolbarItems = new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" };
protected override void OnInitialized()
{
Orders = Enumerable.Range(1, 75).Select((x) =>
{
dynamic d = new ExpandoObject();
d.OrderID = 1000 + x;
d.CustomerID = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)];
d.Freight = (new double[] { 2, 1, 4, 5, 3 })[new Random().Next(5)] * x;
d.OrderDate = (new DateTime[] { new DateTime(2010, 11, 5), new DateTime(2018, 10, 3), new DateTime(1995, 9, 9), new DateTime(2012, 8, 2), new DateTime(2015, 4, 11) })[new Random().Next(5)];
d.ShipCountry = (new string[] { "USA", "UK" })[new Random().Next(2)];
d.Verified = (new bool[] { true, false })[new Random().Next(2)];
return d;
}).Cast<ExpandoObject>().ToList<ExpandoObject>();
}
}
Grid is a generic component which is strongly bound to a model type. There are cases when the model type is unknown during compile type. In such cases you can bound data to the grid as list of DynamicObject.
To know about DynamicObject data binding in Blazor DataGrid component, you can check on this video.
DynamicObject can be bound to datagrid by assigning to the DataSource
property. Grid can also perform all kind of supported data operations and editing in DynamicObject.
The
GetDynamicMemberNames
method of DynamicObject class must be overridden and return the property names to perform data operation and editing while using DynamicObject.
@using Syncfusion.Blazor.Grids
@using System.Dynamic
<SfGrid DataSource="@Orders" AllowPaging="true" Toolbar="@ToolbarItems">
<GridEditSettings AllowAdding="true" AllowDeleting="true" AllowEditing="true"></GridEditSettings>
<GridColumns>
<GridColumn Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field="CustomerID" HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field="OrderDate" HeaderText="Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" EditType="EditType.DatePickerEdit" Width="130"></GridColumn>
<GridColumn Field="Freight" HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code {
private List<string> ToolbarItems = new List<string>(){ "Add","Edit","Delete","Update","Cancel"};
public List<DynamicDictionary> Orders = new List<DynamicDictionary>() { };
protected override void OnInitialized()
{
Orders = Enumerable.Range(1, 1075).Select((x) =>
{
dynamic d = new DynamicDictionary();
d.OrderID = 1000 + x;
d.CustomerID = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)];
d.Freight = (new double[] { 2, 1, 4, 5, 3 })[new Random().Next(5)] * x;
d.OrderDate = DateTime.Now.AddDays(-x);
return d;
}).Cast<DynamicDictionary>().ToList<DynamicDictionary>();
}
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
{
return this.dictionary?.Keys;
}
}
}
To bind remote data to datagrid component, assign service data as an instance of SfDataManager
to the DataSource
property or by usingSfDataManager
component. To interact with remote data source, provide the endpoint Url.
When using
SfDataManager
for data binding then the TValue must be provided explicitly in the datagrid component. By default,SfDataManager
uses ODataAdaptor for remote data-binding.
OData is a standardized protocol for creating and consuming data. You can retrieve data from OData service using the SfDataManager
. Refer to the following code example for remote Data binding using OData service.
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true">
<SfDataManager Url="https://js.syncfusion.com/ejServices/Wcf/Northwind.svc/Orders" Adaptor="Adaptors.ODataAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.ShipCountry) HeaderText="Ship Country" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public class Order {
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
public string ShipCountry { get; set; }
}
}
The ODataV4 is an improved version of OData protocols, and the SfDataManager
can also retrieve and consume OData v4 services. For more details on OData v4 services, refer to the OData documentation. To bind OData v4 service, use the ODataV4Adaptor.
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true">
<SfDataManager Url="https://services.odata.org/V4/Northwind/Northwind.svc/Orders/" Adaptor="Adaptors.ODataV4Adaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public class Order {
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
You can use WebApiAdaptor to bind datagrid with Web API created using OData endpoint.
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true">
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/Orders" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public class Order {
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
The response object from the Web API should contain properties, Items and Count, whose values are a collection of entities and total count of the entities, respectively.
The sample response object should look like this:
{
Items: [{..}, {..}, {..}, ...],
Count: 830
}
It is possible to render the datasource in DataGrid after initial rendering. This can be achieved by conditionally enabling the SfDataManager
component after datagrid rendering.
The following sample code demonstrates enabling data manager condition in the DataGrid on button click,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfButton OnClick="Enable" CssClass="e-primary" IsPrimary="true" Content="Enable data manager"></SfButton>
<SfGrid TValue="Order" AllowPaging="true">
<GridPageSettings PageSize="10"></GridPageSettings>
@if(IsInitialRender)
{
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/Orders" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
}
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public bool IsInitialRender = false;
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
public void Enable()
{
// Enabling condition to render the data manager
this.IsInitialRender = true;
}
}
The following GIF represents dynamically rendering data manager in DataGrid,
To add a custom parameter to the data request, use the addParams method of Query class. Assign the Query object with additional parameters to the datagrid’s Query
property.
The following sample code demonstrates sending additional paramaters using the Query property,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true" Query=@GridQuery>
<GridPageSettings PageSize="10"></GridPageSettings>
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/Orders" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public string ParamValue = "true";
public Query GridQuery { get; set; }
protected override void OnInitialized() {
GridQuery = new Query().AddParams("ej2grid", ParamValue);
}
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
During server interaction from the datagrid, sometimes server-side exceptions might occur. These error messages or exception details can be acquired in client-side using the OnActionFailure
event.
The argument passed to the OnActionFailure
event contains the error details returned from the server.
The following sample code demonstrates notifying user when server-side exception has occurred,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<span class="error">@ErrorDetails</span>
<SfGrid TValue="Order" AllowPaging="true">
<GridEvents TValue="Order" OnActionFailure="@ActionFailure"></GridEvents>
<GridPageSettings PageSize="10"></GridPageSettings>
<SfDataManager Url="https://some.com/invalidUrl" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
<style>
.error {
color: red;
}
</style>
@code{
public string ErrorDetails = "";
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
public void ActionFailure(FailureEventArgs args)
{
this.ErrorDetails = "Server exception: 404 Not found";
StateHasChanged();
}
}
To add a custom headers to the data request, use the Headers
property of the SfDataManager
.
The following sample code demonstrates adding custom headers to the SfDataManager
request,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true">
<GridPageSettings PageSize="10"></GridPageSettings>
<SfDataManager Headers=@HeaderData Url="https://ej2services.syncfusion.com/production/web-services/api/Orders" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
private IDictionary<string, string> HeaderData = new Dictionary<string, string>();
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
It is possible to dynamically modify datagrid’s Query
property value.
The following sample code demonstrates achieving this,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<SfButton Content="Modify query data" OnClick="BtnClick"></SfButton>
<SfGrid TValue="Order" @ref="GridObj" AllowPaging="true" Query="@QueryData">
<GridPageSettings PageSize="10"></GridPageSettings>
<SfDataManager Url="https://services.odata.org/V4/Northwind/Northwind.svc/Orders" Adaptor="Adaptors.ODataV4Adaptor">
</SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public SfGrid<Order> GridObj;
private Query QueryData = new Query().Where("CustomerID", "equal", "VINET");
private Query UpdatedQueryData = new Query().Where("CustomerID", "equal", "HANAR");
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public double? Freight { get; set; }
}
public void BtnClick()
{
QueryData = UpdatedQueryData;
}
}
The following GIF represents dynamically modifying the query property in DataGrid,
The following examples demonstrate,how to consume data from SQL Server using Microsoft SqlClient and bound it to Blazor DataGrid. You can achieve this requirement by using Custom Adaptor
.
Before the implementation, add required NuGet like Microsoft.Data.SqlClient and Syncfusion.Blazor in your application. In the below sample, Custom Adaptor can be created as a Component. In custom adaptor Read method you can get grid action details like paging, filtering, sorting information etc., using DataManagerRequest.
Based on the DataManagerRequest, you can form SQL query string (to perform paging) and execute the SQL query and retrieve the data from database using SqlDataAdapter. The Fill method of the DataAdapter is used to populate a DataSet with the results of the SelectCommand of the DataAdapter, then converted the DataSet into List and return Result and Count pair object in Read method to bind the data to Grid.
@using Syncfusion.Blazor.Grids;
@using Syncfusion.Blazor.Data;
@using Syncfusion.Blazor;
<SfGrid TValue="Order" AllowPaging="true">
<SfDataManager Adaptor="Adaptors.CustomAdaptor">
<CustomAdaptorComponent></CustomAdaptorComponent>
</SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsIdentity="true" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120">
</GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code{
SfGrid<Order> Grid { get; set; }
public static List<Order> Orders { get; set; }
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
}
}
@using Syncfusion.Blazor;
@using Syncfusion.Blazor.Data;
@using Newtonsoft.Json
@using static EFGrid.Pages.Index;
@using Microsoft.Data.SqlClient;
@using System.Data;
@using System.IO;
@using Microsoft.AspNetCore.Hosting;
@inject IHostingEnvironment _env
@inherits DataAdaptor<Order>
<CascadingValue Value="@this">
@ChildContent
</CascadingValue>
@code {
[Parameter]
[JsonIgnore]
public RenderFragment ChildContent { get; set; }
public static DataSet CreateCommand(string queryString, string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
DataSet dt = new DataSet();
try
{
connection.Open();
adapter.Fill(dt);// using sqlDataAdapter we process the query string and fill the data into dataset
}
catch (SqlException se)
{
Console.WriteLine(se.ToString());
}
finally
{
connection.Close();
}
return dt;
}
}
// Performs data Read operation
public override object Read(DataManagerRequest dm, string key = null)
{
string appdata = _env.ContentRootPath;
string path = Path.Combine(appdata, "App_Data\\NORTHWND.MDF");
string str = $"Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename='{path}';Integrated Security=True;Connect Timeout=30";
// based on the skip and take count from DataManagerRequest here we formed SQL query string
string qs = "SELECT OrderID, CustomerID FROM dbo.Orders ORDER BY OrderID OFFSET " + dm.Skip + " ROWS FETCH NEXT " + dm.Take + " ROWS ONLY;";
DataSet data = CreateCommand(qs, str);
Orders = data.Tables[0].AsEnumerable().Select(r => new Order
{
OrderID = r.Field<int>("OrderID"),
CustomerID = r.Field<string>("CustomerID")
}).ToList(); // here we convert dataset into list
IEnumerable<Order> DataSource = Orders;
SqlConnection conn = new SqlConnection(str);
conn.Open();
SqlCommand comm = new SqlCommand("SELECT COUNT(*) FROM dbo.Orders", conn);
Int32 count = (Int32)comm.ExecuteScalar();
return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource;
}
}
- In this
sample
,paging action is handled for Blazor grid based on your need you can extend the given logic for other operations.- For performing data manipulation, you can override available methods such as Insert, Update and Remove of the Custom Adaptor.
You need to follow the below steps to consume data from the Entity Framework in the datagrid component.
The first step is to create a DBContext class called OrderContext to connect to a Microsoft SQL Server database.
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EFGrid.Shared.Models;
namespace EFGrid.Shared.DataAccess
{
public class OrderContext : DbContext
{
public virtual DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename='F:\blazor\EFGrid - CRUD - P6\EFGrid.Shared\App_Data\NORTHWND.MDF';Integrated Security=True;Connect Timeout=30");
}
}
}
}
Now you need to create a class named OrderDataAccessLayer, which act as data access layer for retrieving the records and also insert, update and delete the records from the database table.
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EFGrid.Shared.Models;
namespace EFGrid.Shared.DataAccess
{
public class OrderDataAccessLayer
{
OrderContext db = new OrderContext();
public DbSet<Order> GetAllOrders()
{
try
{
return db.Orders;
}
catch
{
throw;
}
}
}
}
A Web API Controller has to be created which allows datagrid directly to consume data from the Entity framework.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using EFGrid.Shared.DataAccess;
using EFGrid.Shared.Models;
namespace WebApplication1.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
OrderDataAccessLayer db = new OrderDataAccessLayer();
[HttpGet]
public object Get()
{
IQueryable<Order> data = db.GetAllOrders().AsQueryable();
var count = data.Count();
var queryString = Request.Query;
if (queryString.Keys.Contains("$inlinecount"))
{
StringValues Skip;
StringValues Take;
int skip = (queryString.TryGetValue("$skip", out Skip)) ? Convert.ToInt32(Skip[0]) : 0;
int top = (queryString.TryGetValue("$top", out Take)) ? Convert.ToInt32(Take[0]) : data.Count();
return new { Items = data.Skip(skip).Take(top), Count = count };
}
else
{
return data;
}
}
}
}
Now you can configure the datagrid using the ‘SfDataManager’ to interact with the created Web API and consume the data appropriately. To interact with web api, you need to use WebApiAdaptor.
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Grids
<SfGrid TValue="Order" AllowPaging="true" >
<SfDataManager Url="api/Default" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" IsIdentity="true" TextAlign="@Syncfusion.Blazor.Grids.TextAlign.Right" Width="90"></GridColumn>
<GridColumn Field="CustomerID" HeaderText="Customer ID" Width="90"></GridColumn>
<GridColumn Field="EmployeeID" HeaderText="Employee ID" Width="90"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public class Order {
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
}
To perform datagrid CRUD operation using Entity Framework. You can refer here
.
You can find the fully working sample
here
.
It is possible to call web api from the blazor WebAssembly(client-side) app. This can be used for sending Http requests to fetch data from web api and bind them in the DataGrid’s data source. The requests are sent using HttpClient
service.
This can be achieved by initially injecting the HttpClient
instance in the app.
@using System.Net.Http
@inject HttpClient Http
After that the data to be fetched is defined in the api controller of the blazor WebAssembly app.
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : ControllerBase
{
List<Employee> employee = new List<Employee>();
[HttpGet]
public object Get()
{
employee.Add(new Employee { EmployeeID = 1, FirstName = "Andrew", LastName = "Fuller", Title = "Branch Manager" });
employee.Add(new Employee { EmployeeID = 2, FirstName = "Nancy", LastName = "Leverling", Title = "Product Manager" });
employee.Add(new Employee { EmployeeID = 3, FirstName = "Anne", LastName = "Dodsworth", Title = "Team Lead" });
employee.Add(new Employee { EmployeeID = 4, FirstName = "Laura", LastName = "Callahan", Title = "Product Manager" });
employee.Add(new Employee { EmployeeID = 5, FirstName = "Michael", LastName = "Suyama", Title = "Team Lead" });
employee.Add(new Employee { EmployeeID = 6, FirstName = "Robert", LastName = "King", Title = "Developer" });
employee.Add(new Employee { EmployeeID = 7, FirstName = "Janet", LastName = "Peacock", Title = "Developer" });
employee.Add(new Employee { EmployeeID = 8, FirstName = "Steven", LastName = "Buchanan", Title = "Developer" });
employee.Add(new Employee { EmployeeID = 9, FirstName = "Margaret", LastName = "Davolio", Title = "Developer" });
return employee;
}
}
public class Employee
{
public int? EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title { get; set; }
}
Then using the GetJsonAsync
method request is sent to the api controller for fetching data which is bounded to the DataGrid’s data source
@using Syncfusion.Blazor.Grids
@inject HttpClient Http
<SfGrid DataSource="@Empdata" AllowPaging="true">
<GridPageSettings PageSize="7"></GridPageSettings>
<GridColumns>
<GridColumn Field=@nameof(Employee.EmployeeID) HeaderText="Employee ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Employee.FirstName) HeaderText="First Name" Width="120"></GridColumn>
<GridColumn Field=@nameof(Employee.LastName) HeaderText="Last Name" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Employee.Title) HeaderText="Title" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public List<Employee> Empdata { get; set; }
protected override async Task OnInitializedAsync()
{
Empdata = await Http.GetJsonAsync<List<Employee>>("api/Employee");
}
public class Employee
{
public int? EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title { get; set; }
}
}
The above steps are processed in the blazor WebAssembly app which has the preconfigured
HttpClient
service. For blazor server apps, web api calls are created usingIHttpClientFactory
. More information on making requests usingIHttpClientFactory
is available in this link.
This ObservableCollection(dynamic data collection) provides notifications when items added, removed and moved. The implement INotifyCollectionchanged notifies when dynamic changes of add,remove, move and clear the collection. The implement INotifyPropertyChanged notifies when property value has changed in client side. Here, Order class implements the interface of INotifyPropertyChanged and it raises the event when CustomerID property value was changed.
@using Syncfusion.Blazor.Grids
@using System.Collections.ObjectModel
@using System.ComponentModel
<button id="add" @onclick="AddRecords">Add Data</button>
<button id="del" @onclick="DelRecords">Delete Data</button>
<button id="update" @onclick="UpdateRecords">Update Data</button>
<SfGrid DataSource="@GridData" AllowReordering="true">
<GridColumns>
<GridColumn Field=@nameof(OrdersDetailsObserveData.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="@TextAlign.Center" HeaderTextAlign="@TextAlign.Center" Width="140"></GridColumn>
<GridColumn Field=@nameof(OrdersDetailsObserveData.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(OrdersDetailsObserveData.Freight) HeaderText="Freight" EditType="EditType.NumericEdit" Format="C2" Width="140" TextAlign="@TextAlign.Right" HeaderTextAlign="@TextAlign.Right"></GridColumn>
<GridColumn Field=@nameof(OrdersDetailsObserveData.OrderDate) HeaderText="Order Date" EditType="EditType.DatePickerEdit" Format="d" Type="ColumnType.Date" Width="160"></GridColumn>
<GridColumn Field=@nameof(OrdersDetailsObserveData.ShipCountry) HeaderText="Ship Country" EditType="EditType.DropDownEdit" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public ObservableCollection<OrdersDetailsObserveData> GridData { get; set; }
public int Count = 32341;
protected override void OnInitialized()
{
GridData = OrdersDetailsObserveData.GetRecords();
}
public void AddRecords()
{
GridData.Add(new OrdersDetailsObserveData(Count++, "ALFKI", 4343, 2.3 * 43, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
}
public void DelRecords()
{
GridData.Remove(GridData.First());
}
public void UpdateRecords()
{
var a = GridData.First();
a.CustomerID = "Update";
}
public class OrdersDetailsObserveData : INotifyPropertyChanged
{
public OrdersDetailsObserveData()
{
}
public OrdersDetailsObserveData(int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified, DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry, DateTime ShippedDate, string ShipAddress)
{
this.OrderID = OrderID;
this.CustomerID = CustomerId;
this.EmployeeID = EmployeeId;
this.Freight = Freight;
this.ShipCity = ShipCity;
this.Verified = Verified;
this.OrderDate = OrderDate;
this.ShipName = ShipName;
this.ShipCountry = ShipCountry;
this.ShippedDate = ShippedDate;
this.ShipAddress = ShipAddress;
}
public static ObservableCollection<OrdersDetailsObserveData> GetRecords()
{
ObservableCollection<OrdersDetailsObserveData> order = new ObservableCollection<OrdersDetailsObserveData>();
int code = 10000;
for (int i = 1; i < 2; i++)
{
order.Add(new OrdersDetailsObserveData(code + 1, "ALFKI", i + 0, 2.3 * i, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
order.Add(new OrdersDetailsObserveData(code + 2, "ANATR", i + 2, 3.3 * i, true, new DateTime(1990, 04, 04), "Madrid", "Queen Cozinha", "Brazil", new DateTime(1996, 9, 11), "Avda. Azteca 123"));
order.Add(new OrdersDetailsObserveData(code + 3, "ANTON", i + 1, 4.3 * i, true, new DateTime(1957, 11, 30), "Cholchester", "Frankenversand", "Germany", new DateTime(1996, 10, 7), "Carrera 52 con Ave. Bol�var #65-98 Llano Largo"));
order.Add(new OrdersDetailsObserveData(code + 4, "BLONP", i + 3, 5.3 * i, false, new DateTime(1930, 10, 22), "Marseille", "Ernst Handel", "Austria", new DateTime(1996, 12, 30), "Magazinweg 7"));
order.Add(new OrdersDetailsObserveData(code + 5, "BOLID", i + 4, 6.3 * i, true, new DateTime(1953, 02, 18), "Tsawassen", "Hanari Carnes", "Switzerland", new DateTime(1997, 12, 3), "1029 - 12th Ave. S."));
code += 5;
}
return order;
}
public int OrderID { get; set; }
public string CustomerID
{
get { return customerID; }
set
{
customerID = value;
NotifyPropertyChanged("CustomerID");
}
}
public string customerID { get; set; }
public int EmployeeID { get; set; }
public double Freight { get; set; }
public string ShipCity { get; set; }
public bool Verified { get; set; }
public DateTime OrderDate { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public string ShipName { get; set; }
public string ShipCountry { get; set; }
public DateTime ShippedDate { get; set; }
public string ShipAddress { get; set; }
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
The following screenshot represents the DataGrid with Observable Collection.
In ASP.NET Core, by default the JSON results are returned in camelCase format. So datagrid field names are also changed in camelCase.
To avoid this problem, you need to add DefaultContractResolver in Startup.cs file.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor().AddCircuitOptions();
services.AddSingleton<WeatherForecastService>();
services.AddMvc().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
}
Exceptions occurred during grid actions can be handled without stopping application. These error messages or exception details can be acquired using the OnActionFailure
event.
The argument passed to the OnActionFailure
event contains the error details returned from the server.
We recommend you to bind OnActionFailure event during your application development phase, this helps you to find any exceptions. You can pass these exception details to our support team to get solution as early as possible.
The following sample code demonstrates notifying user when server-side exception has occurred during data operation,
@using Syncfusion.Blazor
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Grids
<span class="error">@ErrorDetails</span>
<SfGrid TValue="Order" AllowPaging="true">
<GridEvents TValue="Order" OnActionFailure="@ActionFailure"></GridEvents>
<GridPageSettings PageSize="10"></GridPageSettings>
<SfDataManager Url="https://some.com/invalidUrl" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridColumns>
<GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
<GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
</GridColumns>
</SfGrid>
<style>
.error {
color: red;
}
</style>
@code{
public string ErrorDetails = "";
public class Order
{
public int? OrderID { get; set; }
public string CustomerID { get; set; }
public DateTime? OrderDate { get; set; }
public double? Freight { get; set; }
}
public void ActionFailure(FailureEventArgs args)
{
this.ErrorDetails = "Server exception: 404 Not found";
StateHasChanged();
}
}