Skip to main content
All docs
V26.1
  • GridCustomDataSourceGroupInfo.DataItemCount Property

    Returns the number of items in a group.

    Namespace: DevExpress.Blazor

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

    NuGet Package: DevExpress.Blazor

    Declaration

    public int DataItemCount { get; set; }

    Property Value

    Type Description
    Int32

    The number of items.

    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 GetGroupInfoAsync 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<GridCustomDataSourceGroupInfo>> GetGroupInfoAsync(GridCustomDataSourceGroupingOptions options,
            CancellationToken cancellationToken) {
            var filteredQuery = ApplyFiltering(options.FilterCriteria, _context.Orders);
    
            var summaryQuery = GetGroupByAndSelectQuery(options.SummaryInfo, filteredQuery, false, options.FieldName);
            var resultList = await summaryQuery.ToListAsync(cancellationToken);
    
            var groupInfoList = new List<GridCustomDataSourceGroupInfo>();
            foreach (var result in resultList) {
                var groupInfo = new GridCustomDataSourceGroupInfo() { Value = result["Value"], DataItemCount = (int)result["DataItemCount"] };
    
                var summaryList = new List<object>();
                foreach (var kvp in result) {
                    if (kvp.Key.StartsWith("Summary_")) {
                        summaryList.Add(kvp.Value);
                    }
                }
    
                groupInfo.SummaryValues = summaryList;
                groupInfoList.Add(groupInfo);
            }
    
            return options.DescendingSortOrder
                ? groupInfoList
                    .OrderByDescending(g => g.Value)
                    .ToList()
                : groupInfoList
                    .OrderBy(g => g.Value)
                    .ToList();
        }
        // ...
        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<Dictionary<string, object>> GetGroupByAndSelectQuery(IReadOnlyList<GridCustomDataSourceSummaryInfo> summaryInfoList,
            IQueryable<Order> queryableSource, bool totalSummary, string groupedFieldName = "") {
            IQueryable groupedQuery;
            Type groupedPropertyType;
            if (totalSummary) {
                groupedPropertyType = typeof(int);
                groupedQuery = queryableSource.GroupBy(x => 1);
            } else {
                var parameter = Expression.Parameter(typeof(Order));
                var property = Expression.Property(parameter, groupedFieldName);
                groupedPropertyType = property.Type;
                var groupLambda = Expression.Lambda(property, parameter);
    
                var groupByCall = Expression.Call(typeof(Queryable), "GroupBy", new[] { typeof(Order), groupedPropertyType },
                    queryableSource.Expression, groupLambda);
                groupedQuery = queryableSource.Provider.CreateQuery(groupByCall);
            }
    
            var groupType = typeof(IGrouping<,>).MakeGenericType(groupedPropertyType, typeof(Order));
            var group = Expression.Parameter(groupType);
    
            // defining a dictionary that will hold group info
            var dictItems = new List<ElementInit>();
            var addMethod = typeof(Dictionary<string, object>).GetMethod("Add");
            if (!totalSummary) {
                dictItems.AddRange(new List<ElementInit> {
                    Expression.ElementInit(addMethod, Expression.Constant("Value"),
                        Expression.Convert(Expression.Property(group, "Key"), typeof(object))
                    ),
                    Expression.ElementInit(addMethod, Expression.Constant("DataItemCount"),
                        Expression.Convert(Expression.Call(typeof(Enumerable), "Count",
                            new[] { typeof(Order) }, group), typeof(object))
                    )
                });
            }
    
            for (int i = 0; i < summaryInfoList.Count; i++) {
                var summaryInfo = summaryInfoList[i];
    
                var groupSummaryCall = GetGroupSummaryCall(summaryInfo, group);
                dictItems.Add(Expression.ElementInit(addMethod, Expression.Constant("Summary_" + i),
                    Expression.Convert(groupSummaryCall, typeof(object))));
            }
    
            var dictInit = Expression.ListInit(Expression.New(typeof(Dictionary<string, object>)), dictItems);
    
            // creating the select query
            Type selectFuncType = typeof(Func<,>).MakeGenericType(groupType, typeof(Dictionary<string, object>));
            var selectLambda = Expression.Lambda(selectFuncType, dictInit, group);
            var selectCall = Expression.Call(typeof(Queryable), "Select",
                new[] { groupedQuery.ElementType, typeof(Dictionary<string, object>) },
                groupedQuery.Expression, selectLambda);
    
            return groupedQuery.Provider.CreateQuery<Dictionary<string, object>>(selectCall);
        }
    
        private static Expression GetGroupSummaryCall(GridCustomDataSourceSummaryInfo summaryInfo,
            Expression group) {
            var parameter = Expression.Parameter(typeof(Order));
            var property = Expression.Property(parameter, summaryInfo.FieldName);
            var summaryLambda = Expression.Lambda(property, parameter);
    
            switch (summaryInfo.SummaryType) {
                case GridSummaryItemType.Avg:
                    return Expression.Call(typeof(Enumerable), "Average", new[] { typeof(Order) },
                        group, summaryLambda);
                case GridSummaryItemType.Count:
                    return Expression.Call(typeof(Enumerable), "Count", new[] { typeof(Order) },
                        group);
                case GridSummaryItemType.Max:
                    return Expression.Call(typeof(Enumerable), "Max", new[] { typeof(Order), property.Type },
                        group, summaryLambda);
                case GridSummaryItemType.Min:
                    return Expression.Call(typeof(Enumerable), "Min", new[] { typeof(Order), property.Type },
                        group, summaryLambda);
                case GridSummaryItemType.Sum:
                    return Expression.Call(typeof(Enumerable), "Sum", new[] { typeof(Order) },
                        group, summaryLambda);
                default:
                    throw new NotSupportedException(summaryInfo.SummaryType.ToString());
            }
        }
        // ...
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing) {
            if (!_disposed) {
                if (disposing) {
                    _context?.Dispose();
                }
                _disposed = true;
            }
        }
        // ...
    }
    
    See Also