Skip to main content

DevExpress v24.2 Update — Your Feedback Matters

Our What's New in v24.2 webpage includes product-specific surveys. Your response to our survey questions will help us measure product satisfaction for features released in this major update and help us refine our plans for our next major release.

Take the survey Not interested

GridCustomDataSource Class

Allows you to bind DxGrid and DxTreeList to a custom data source.

Namespace: DevExpress.Blazor

Assembly: DevExpress.Blazor.v24.2.dll

NuGet Package: DevExpress.Blazor

#Declaration

C#
public abstract class GridCustomDataSource

#Remarks

You can bind the Grid to data in the following ways:

The TreeList component supports the following data binding scenarios:

We recommend using the GridCustomDataSource class only if the methods described are unsuitable.

The following code snippet implements a custom data source based on the GridCustomDataSource class:

View Example: Bind the Grid to OData Data Source

cs
using System.Collections;
using Blazor.WebAssembly.Models;
using DevExpress.Blazor;
using DevExpress.Data.Filtering;
using DevExpress.Data.Filtering.Helpers;
using Simple.OData.Client;

namespace Blazor.WebAssembly.Services;

public class SimpleODataClientDataSource : GridCustomDataSource {
    private readonly ODataClient _client;
    public SimpleODataClientDataSource(IHttpClientFactory httpClientFactory)
        => _client = new ODataClient(new ODataClientSettings(httpClientFactory.CreateClient("API"), new Uri("odata/", UriKind.Relative)));

    public override async Task<int> GetItemCountAsync(GridCustomDataSourceCountOptions options, CancellationToken cancellationToken)
        => await ApplyFiltering(options.FilterCriteria, _client.For<Post>()).Count()
            .FindScalarAsync<int>(cancellationToken);

    public override async Task<IList> GetItemsAsync(GridCustomDataSourceItemsOptions options, CancellationToken cancellationToken) {
        var filteredClient = ApplyFiltering(options.FilterCriteria, _client.For<Post>().Top(options.Count).Skip(options.StartIndex));
        return (await ApplySorting(options, filteredClient).FindEntriesAsync(cancellationToken)).ToList();
    }

    private static IBoundClient<Post> ApplyFiltering(CriteriaOperator criteria, IBoundClient<Post> boundClient)
        => !criteria.ReferenceEqualsNull() ? boundClient.Filter(ToSimpleClientCriteria(criteria)) : boundClient;

    private static string ToSimpleClientCriteria(CriteriaOperator criteria)
        => $"{criteria}".Replace("[", "").Replace("]", "");

    private static IBoundClient<Post> ApplySorting(GridCustomDataSourceItemsOptions options, IBoundClient<Post> boundClient) {
        return options.SortInfo != null && options.SortInfo.Any() ? boundClient.OrderBy(options.SortInfo
                .Where(info => !info.DescendingSortOrder).Select(info => info.FieldName).ToArray())
            .OrderByDescending(options.SortInfo
                .Where(info => info.DescendingSortOrder).Select(info => info.FieldName).ToArray()) : boundClient;
    }
    public async Task DeleteAsync(Post instance)
        => await _client.For<Post>().Key(instance.ID).DeleteEntryAsync();

    public async Task AddOrUpdateAsync(Post instance, bool update = false) {
        if (!update) {
            await _client.For<Post>().Set(new { instance.Title, instance.Content }).InsertEntryAsync();
        }
        else {

            await _client.For<Post>().Key(instance.ID).Set(instance).UpdateEntryAsync();
        }
    }
}

During initialization, a GridCustomDataSource descendant sends an additional request to determine the item type. If the item type differs from ExpandoObject, you can specify this type directly in the descendant configuration to avoid additional requests:

cs
private class MyCustomDataSource<T> : GridCustomDataSource {
    protected override Type DataItemType => typeof(T)
    // ...
}

#Inheritance

See Also