Skip to main content

GridCustomDataSourceItemsOptions.StartIndex Property

Specifies the index of the first item to be selected.

Namespace: DevExpress.Blazor

Assembly: DevExpress.Blazor.Grid.v26.1.dll

NuGet Package: DevExpress.Blazor

Declaration

public int StartIndex { get; }

Property Value

Type Description
Int32

The start index.

Remarks

If standard data binding modes do not meet specific business requirements, you can implement your own data provider. To do so, create a GridCustomDataSource descendant and assign it to the Grid or TreeList component’s Data property.

The following code snippet implements a custom data provider’s GetItemsAsync method:

View Example: Custom Data Source Binding using Entity Framework Core

using DevExpress.Blazor;
using DevExpress.Data.Filtering;
using DevExpress.Data.Filtering.Helpers;
using CustomDataSource.Models;
using System.Collections;
using System.Linq.Expressions;
using DevExpress.Data.Linq;
using DevExpress.Data.Linq.Helpers;
using Microsoft.EntityFrameworkCore;

namespace CustomDataSource.Services;

public class OrdersDataSource : GridCustomDataSource, IDisposable {
    protected override Type DataItemType => typeof(Order);
    private readonly NorthwindContext _context;
    private bool _disposed = false;

    public OrdersDataSource(IDbContextFactory<NorthwindContext> contextFactory) {
        _context = contextFactory.CreateDbContext();
    } 
    // ...
    public override async Task<IList> GetItemsAsync(GridCustomDataSourceItemsOptions options, CancellationToken cancellationToken) {
        var filteredQuery = ApplyFiltering(options.FilterCriteria, _context.Orders);

        if (options.Count >= 0) {
            return await ApplySorting(options, filteredQuery)
                .Skip(options.StartIndex)
                .Take(options.Count)
                .ToListAsync(cancellationToken);
        }

        return await ApplySorting(options, filteredQuery).ToListAsync(cancellationToken);
    }
    // ...
    private static IQueryable<Order> ApplyFiltering(CriteriaOperator criteria, IQueryable<Order> queryableSource) {
        return !criteria.ReferenceEqualsNull()
            ? (IQueryable<Order>)queryableSource.AppendWhere(
                new CriteriaToEFExpressionConverter(queryableSource.Provider.GetType()), criteria)
            : queryableSource;
    }

    private static IQueryable<Order> ApplySorting(GridCustomDataSourceItemsOptions options, IQueryable<Order> queryableSource) {
        if (options.SortInfo != null) {
            foreach (var sortInfo in options.SortInfo) {
                queryableSource = SortByField(sortInfo.FieldName, sortInfo.DescendingSortOrder, queryableSource);
            }
        }

        return queryableSource;
    }

    private static IQueryable<Order> SortByField(string fieldName, bool descendingOrder, IQueryable<Order> queryableSource) {
        var lambda = GetTypedLambda(fieldName);
        if (queryableSource.Expression.Type != typeof(IOrderedQueryable<Order>)) {
            return !descendingOrder
                ? queryableSource.OrderBy(lambda)
                : queryableSource.OrderByDescending(lambda);
        }

        return !descendingOrder
            ? ((IOrderedQueryable<Order>)queryableSource).ThenBy(lambda)
            : ((IOrderedQueryable<Order>)queryableSource).ThenByDescending(lambda);
    }

    private static Expression<Func<Order, object>> GetTypedLambda(string fieldName) {
        var parameter = Expression.Parameter(typeof(Order));
        var property = Expression.Property(parameter, fieldName);
        var lambda = Expression.Lambda<Func<Order, object>>(Expression.Convert(property, typeof(object)), parameter);
        return lambda;
    }
    // ...
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) {
        if (!_disposed) {
            if (disposing) {
                _context?.Dispose();
            }
            _disposed = true;
        }
    }
    // ...
}
See Also