Skip to main content

Bind to Data

  • 17 minutes to read

This document describes how to bind the Blazor Grid to data in different scenarios.

Use the Data parameter to specify a data source. To display data within the Grid, declare DxGridDataColumn objects in the Columns template and use each object’s FieldName property to assign data fields.

Synchronous Data Binding

You can bind the Grid to a data collection available during synchronous component initialization.

  1. Bind the Data parameter to a C# field or property.
  2. Populate this field or property with data in the OnInitialized lifecycle method.
@inject WeatherForecastService ForecastService

<DxGrid Data="@Data">
    <Columns>
        <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
        <DxGridDataColumn FieldName="TemperatureC" Caption="@("Temp. (\x2103)")" Width="120px" />
        <DxGridDataColumn FieldName="TemperatureF" Caption="@("Temp. (\x2109)")" Width="120px" />
        <DxGridDataColumn FieldName="Forecast" />
        <DxGridDataColumn FieldName="CloudCover" />
    </Columns>
</DxGrid>

@code {
    object Data { get; set; }

    protected override void OnInitialized() {
        Data = ForecastService.GetForecast();
    }
}

Blazor Grid Data Binding

Run Demo: Grid - Data Binding

Asynchronous Data Binding

The Grid can also use a data collection that becomes available after asynchronous component initialization.

  1. Bind the Data parameter to a C# field or property.
  2. Populate this field or property with data in the OnInitializedAsync lifecycle method (use the await operator).
@inject WeatherForecastService ForecastService

<DxGrid Data="@Data">
    <Columns>
        <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
        <DxGridDataColumn FieldName="TemperatureC" Caption="@("Temp. (\x2103)")" Width="120px" />
        <DxGridDataColumn FieldName="TemperatureF" Caption="@("Temp. (\x2109)")" Width="120px" />
        <DxGridDataColumn FieldName="Forecast" />
        <DxGridDataColumn FieldName="CloudCover" />
    </Columns>
</DxGrid>

@code {
    object Data { get; set; }

    protected override async Task OnInitializedAsync() {
        Data = await ForecastService.GetForecastAsync();
    }
}

Blazor Grid Data Binding

Run Demo: Grid - Asynchronous Data Binding

Observable Data Collections

You can bind the Grid to a data collection that implements the INotifyCollectionChanged or IBindingList interface. For instance, you can use the standard ObservableCollection<T> or BindingList<T> objects. These collections notify the Grid about changes, such as add, remove, collection refresh operations, and so on. The Grid updates its data automatically to reflect these changes.

Each item in such collections should also implement the INotifyPropertyChanged interface to notify the Grid when a property value changes.

The following sample binds the Grid to an ObservableCollection and adds new items to this collection on button clicks. The INotifyPropertyChanged interface is not implemented because properties of collection items do not change.

@using System.Collections.ObjectModel

<DxButton Text="Add New Day"
          Click="(e) => AddNewForecast()" />

<p/>
<DxGrid Data="@WeatherForecastData">
    <Columns>
        <DxGridDataColumn FieldName="Date" DisplayFormat="D" />
        <DxGridDataColumn FieldName="TemperatureC" Caption="@("Temp. (\x2103)")" />
        <DxGridDataColumn FieldName="TemperatureF" Caption="@("Temp. (\x2109)")" />
    </Columns>
</DxGrid>

@code {
    int DayCount { get; set; } = 0;
    ObservableCollection<WeatherForecast> WeatherForecastData { get; set; }
    static readonly Random Rnd = new Random();

    protected override void OnInitialized() {
        WeatherForecastData = new ObservableCollection<WeatherForecast>();
        foreach (var date in Enumerable.Range(1, 5).Select(i => DateTime.Now.Date.AddDays(i))) {
            AddNewForecast();
        }
    }

    void AddNewForecast() {
        WeatherForecastData.Add(new WeatherForecast() {
            Date = DateTime.Now.Date.AddDays(++DayCount),
            TemperatureC = Rnd.Next(10, 20)
        });
    }
}

Blazor Grid Observable Collection

Note

After you bind a dynamic data collection to the Grid, the collection sends notifications after each change separately. When you make a sequence of modifications (for instance, in a for loop), the Grid is re-rendered after each iteration.

Run Demo: Grid - Observable Data Collections

Large Data (Server Mode Sources)

In Blazor Server applications, the Grid supports Sever Mode data sources designed to work with large data collections.

When you assign a data collection to the Data property directly, the Grid stores all data records in memory. This increases memory consumption if the collection is large. All data processing operations (sort, group, filter, and so on) are performed within the Blazor application and can cause lags.

When you use Server Mode data sources, the Grid loads data in small portions on demand (instead of the entire dataset). This helps reduce memory consumption. All data shaping operations are delegated to underlying services (such as EF Core, XPO, and so on). These services process operations more efficiently and enhance overall performance. Note that these data sources have specifics and limitations.

Data Source Types

The Grid includes two types of Server Mode data sources:

Server Mode Data Source
A synchronous data source that locks the UI and does not respond to user actions while data is retrieved.
Instant Feedback Data Source
An asynchronous data source that loads data in a background thread and does not freeze the UI. The Grid displays skeletons and data load indicators when data is not retrieved.

The following table lists cross-platform Server Mode data sources compatible with the Blazor Grid:

Data Access Technology

Server Mode Data Source

Instant Feedback Data Source

Entity Framework Core

EntityServerModeSource

EntityInstantFeedbackSource

XPO

XPServerCollectionSource

XPServerModeView

XPInstantFeedbackSource

XPInstantFeedbackView

Parallel LINQ

PLinqServerModeSource

PLinqInstantFeedbackSource

OData

ODataServerModeSource

ODataInstantFeedbackSource

How to Use Server Mode

Do the following to use a Server Mode data source in the Grid:

  1. Add a reference to a data source’s namespace (for instance, DevExpress.Data.Linq for EF Core data sources).
  2. Create a data source instance and specify its parameters. For more information about data sources and their settings, refer to the topics in the table above.
  3. Bind the data source instance to the Grid’s Data parameter.
  4. Implement the IDisposable interface on the Razor page (use the @implements directive). Within the page’s Dispose method, check the data source instance for null and dispose of it.

The example below shows how to use an EntityInstantFeedbackSource in the Grid. Create a data source instance and specify two required parameters:

KeyExpression
Identifies the name of the entity model’s key property. This property should correspond to the primary key from an underlying database. If the database does not contain the primary key, you cannot use this database as a Server Mode data source.
QueryableSource
Defines a queryable data source from an EF Core data context (for instance, DbSet<T>).

For more information on how to use EF Core, refer to the following topic: Bind Components to Data with Entity Framework Core.

@using Microsoft.EntityFrameworkCore
@using DevExpress.Data.Linq
@inject IDbContextFactory<NorthwindContext> NorthwindContextFactory
@implements IDisposable

<DxGrid Data="InstantFeedbackSource"> 
    <Columns>
        <DxGridDataColumn FieldName="ShipName" />
        <DxGridDataColumn FieldName="ShipCity" />
        <DxGridDataColumn FieldName="ShipCountry" />
        <DxGridDataColumn FieldName="Freight"  />
        <DxGridDataColumn FieldName="OrderDate" />
        <DxGridDataColumn FieldName="ShippedDate" />
    </Columns>
</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;
        });
    }

    public void Dispose() {
        InstantFeedbackSource?.Dispose();
        Northwind?.Dispose();
    }
}

Blazor Grid Instant Feedback Source

Run Demo: Grid - Large Data (Instant Feedback Source)

Common Specifics and Limitations

The Grid imposes the following specifics and limitations when you use Server Mode data sources:

Instant Feedback Source Specifics

An Instant Feedback data source loads data asynchronously in small portions (instead of the entire dataset). Call the WaitForInstantFeedbackRowLoadAsync(Int32) method to ensure that the specified data row is loaded. For instance, call this method before methods that accept a row’s visible index as a parameter (SelectRow, StartEditRowAsync, and so on).

If a data source’s AreSourceRowsThreadSafe option is set to false (the default value), you cannot cast a data item and use the {DataItem.FieldName} notation. Call the GetDataItemValue(Object, String) method to obtain the data item’s field value. Note that this method does not provide access to the data source object and you cannot handle events or call methods related to the object.

Large Data (Queryable Collections)

In Blazor Server and Blazor WebAssembly applications, you can use the GridDevExtremeDataSource<T> to bind the Grid to a large IQueryable<T> data collection.

When you use this data source, the Grid delegates data processing operations to an underlying query provider (such as LINQ to Objects, EF Core, and so on). The Grid only loads data required for screen display. This helps enhance overall performance and application responsiveness, and reduces memory consumption. Data source implementation is based on the DevExpress DevExtreme.AspNet.Data library.

Local Queryable Collections

Follow the steps below to bind the Grid to a large IQueryable<T> data collection stored locally:

  1. Create a GridDevExtremeDataSource class instance and pass your IQueryable<T> data collection as the constructor parameter.
  2. Assign this instance to the Grid’s Data property.

The example below uses Entity Framework Core. For more information on this data access technology, refer to the following topic: Bind Components to Data with Entity Framework Core.

@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<NorthwindContext> NorthwindContextFactory
@implements IDisposable

<DxGrid Data="GridDataSource">
    <Columns>
        <DxGridDataColumn FieldName="OrderDate" DisplayFormat="d" />
        <DxGridDataColumn FieldName="CustomerName" />
        <DxGridDataColumn FieldName="Country" />
        <DxGridDataColumn FieldName="Freight" DisplayFormat="n2" />
        <DxGridDataColumn FieldName="ExtendedPrice" DisplayFormat="c" />
    </Columns>
</DxGrid>

@code {
    object GridDataSource { get; set; }
    NorthwindContext Northwind { get; set; }

    protected override void OnInitialized() {
        Northwind = NorthwindContextFactory.CreateDbContext();
        GridDataSource = new GridDevExtremeDataSource<Invoice>(Northwind.Invoices);
    }

    public void Dispose() {
        Northwind?.Dispose();
    }
}

Blazor Grid Large Queryable

Run Demo: Grid - Large Data (Queryable)

Queryable Collections as HTTP Services

Follow the steps below to bind the Grid to a large data collection published as an HTTP service:

  1. Create a GridDevExtremeDataSource class instance and pass two constructor parameters:

    • An HttpClient object that sends HTTP requests and receives HTTP responses from the specified URL.
    • A URL to the service’s controller action that processes HTTP requests (see step 3).
  2. Assign the GridDevExtremeDataSource class instance to the Grid’s Data property.

  3. On the service side, implement an API controller. Create action methods that use the DevExtreme.AspNet.Data library’s DataSourceLoader class to create a LoadResult object based on load options.
@inject HttpClient HttpClient

<DxGrid Data="@Data">
    <Columns>
        <DxGridDataColumn FieldName="CustomerID" />
        <DxGridDataColumn FieldName="OrderDate" DisplayFormat="d" />
        <DxGridDataColumn FieldName="Freight" DisplayFormat="n2" />
        <DxGridDataColumn FieldName="ShipCountry" />
    </Columns>
</DxGrid>

@code {
    object Data { get; set; }

    public class Order {
        public string CustomerID { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal Freight { get; set; }
        public string ShipCountry { get; set; }
    }

    protected override async Task OnInitializedAsync() {
        var uri = new Uri("https://js.devexpress.com/Demos/NetCore/api/DataGridWebApi/Orders");
        Data = new GridDevExtremeDataSource<Order>(HttpClient, uri);
    }
}

Blazor Grid Large Queryable HTTP Service

Run Demo: Grid - Large Data (Queryable as HTTP Service)

You can also generate and send custom HTTP requests:

  1. Implement an asynchronous function that returns a Task<Stream> object and accepts two parameters:

    • A URL to the service’s controller action.
    • A CancellationToken object that propagates a cancellation notification.
  2. Create a GridDevExtremeDataSource class instance and pass two constructor parameters (the newly created function and the URL to the service’s controller action).

  3. Assign the GridDevExtremeDataSource instance to the Grid’s Data property.

The following code snippet adds an authorization header to HTTP requests. Note that you should process authorization information in the service’s controller.

@*...*@

@code {
    // ...

    protected override async Task OnInitializedAsync() {
        var uri = new Uri("https://js.devexpress.com/Demos/NetCore/api/DataGridWebApi/Orders");
        Data = new GridDevExtremeBasedDataSource<Product>(ExecuteDataSourceHttpRequest, url);
    }

    async Task<Stream> ExecuteDataSourceHttpRequest(Uri url, CancellationToken cancellationToken) {
        using var request = new HttpRequestMessage(HttpMethod.Get, url);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "...");
        var response = await HttpClient.SendAsync(request);
        return await response.Content.ReadAsStreamAsync();
    }
}

Limitations

The GridDevExtremeDataSource imposes the following limitations on Grid features that are available when you assign a data collection to the Data property directly:

The Grid loads only data required to display the current page. You cannot use the Grid’s API members that get data items outside the visible range (for instance, from the next page). Do not call methods that accept a row’s visible index as a parameter (GetDataItem(Int32), SelectRow(Int32, Boolean), StartEditRowAsync(Int32), and so on).

If you have a reference to a data item that is outside the visible display range, you can use API members that operate on data items directly: SelectDataItem(Object, Boolean), StartEditDataItemAsync(Object), and so on.

Unbound Columns

The Grid allows you to add unbound columns whose values are not stored in the assigned data collection. You can calculate column values in two ways:

  • Specify the UnboundExpression that calculates unbound column values based on other column values.
  • Handle the UnboundColumnData event to supply unique column values based on custom logic.

For more information and examples, refer to the following topic: Create an Unbound Column.