The Syncfusion Flutter DataGrid provides built-in support to display concise information about the rows by using the table summary rows. Table summary rows allow you to display summarized information about the rows in the DataGrid, such as the sum, average, maximum, and minimum value of a column. This can be useful when you want to provide a quick overview of the data in the DataGrid. In this article, we will show you how to format the column and its summary data in the DataGrid as a currency format. We will use the built-in table summary types provided by DataGrid to achieve this. STEP 1: Import the following package in your project to access the table summary types provided by the DataGrid. import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:intl/intl.dart'; STEP 2: Initialize the SfDataGrid widget with all the required properties. late EmployeeDataSource _employeeDataSource; List<Employee> employees = <Employee>[]; @override void initState() { super.initState(); employees = getEmployeeData(); _employeeDataSource = EmployeeDataSource(employees); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Flutter SfDataGrid')), body: SfDataGrid( source: _employeeDataSource, columns: [ GridColumn( columnName: 'id', label: Container( padding: const EdgeInsets.symmetric(horizontal: 8.0), alignment: Alignment.center, child: const Text('ID'), ), ), GridColumn( columnName: 'name', label: Container( padding: const EdgeInsets.symmetric(horizontal: 8.0), alignment: Alignment.center, child: const Text('Name'), ), ), GridColumn( columnName: 'designation', label: Container( padding: const EdgeInsets.symmetric(horizontal: 8.0), alignment: Alignment.center, child: const Text('Designation'), ), ), GridColumn( columnName: 'salary', label: Container( padding: const EdgeInsets.symmetric(horizontal: 8.0), alignment: Alignment.center, child: const Text('Salary '), ), ), ], columnWidthMode: ColumnWidthMode.auto, tableSummaryRows: [ GridTableSummaryRow( showSummaryInRow: false, columns: [ const GridSummaryColumn( name: 'Sum', columnName: 'salary', summaryType: GridSummaryType.sum) ], position: GridTableSummaryRowPosition.bottom) ], ), ); } STEP 3: Create a data source class by extending DataGridSource for mapping data to the SfDataGrid. In the buildTableSummaryCellWidget method, you can format the table summary value using the NumberFormat.currency constructor. This method is called for each table summary cell, and it returns the widget that should be displayed in the cell. You can also format the cell value in the buildRow method. This method is called for each row in the DataGrid, and it returns the widget that should be displayed in the row. class EmployeeDataSource extends DataGridSource { EmployeeDataSource(List<Employee> employees) { buildDataGridRow(employees); } void buildDataGridRow(List<Employee> employeeData) { dataGridRow = employeeData.map<DataGridRow>((employee) { return DataGridRow(cells: [ DataGridCell<int>(columnName: 'id', value: employee.id), DataGridCell<String>(columnName: 'name', value: employee.name), DataGridCell<String>( columnName: 'designation', value: employee.designation), DataGridCell<double>(columnName: 'salary', value: employee.salary) ]); }).toList(); } List<DataGridRow> dataGridRow = <DataGridRow>[]; @override List<DataGridRow> get rows => dataGridRow.isEmpty ? [] : dataGridRow; final formatter = NumberFormat.currency(symbol: '\$'); @override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map<Widget>((dataGridCell) { return Container( alignment: Alignment.center, child: Text( dataGridCell.columnName == 'salary' ? formatter.format(dataGridCell.value) : dataGridCell.value.toString(), )); }).toList()); } @override Widget? buildTableSummaryCellWidget( GridTableSummaryRow summaryRow, GridSummaryColumn? summaryColumn, RowColumnIndex rowColumnIndex, String summaryValue) { String value = formatter.format(double.parse(summaryValue)); return Container(alignment: Alignment.center, child: Text(value)); } } You can download the example from GitHub. Conclusion I hope you enjoyed learning about how to show the column and its summary value in currency format in Flutter DataTable (SfDataGrid). You can refer to our Flutter DataGrid’s feature tour page to know about its other groundbreaking feature representations. You can also explore our Flutter DataGrid documentation to understand how to present and manipulate data. For current customers, you can check out our WinForms components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our Flutter DataGrid and other Flutter components. If you have any queries or require clarifications, please let us know in comments below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
In WinForms DataGrid, you can change the group Expander color by setting SfDataGrid Style CaptionSummary RowStyle ExpanderColor property. sfDataGrid1.Style.CaptionSummaryRowStyle.ExpanderColor = Color.Red; View sample in GitHub.ConclusionI hope you enjoyed learning about how to change the captionsummary expander indicator color in WinForms DataGrid.You can refer to our WinForms DataGrid feature tour page to know about its other groundbreaking feature representations documentation and how to quickly get started for configuration specifications. You can also explore our WinForms DataGrid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
WPF DataGrid (SfDataGrid) allows you to add column to CaptionSummaryRow at run time by adding GridSummaryColumn to CaptionSummaryRow.SummaryColumns. dataGrid.Loaded += DataGrid_Loaded; addColumn.Click += addColumn_Click;private void DataGrid_Loaded(object sender, System.Windows.RoutedEventArgs e) { this.dataGrid.CaptionSummaryRow = new GridSummaryRow() { ShowSummaryInRow = true, Title = "Total Sales: {SalesAmount} for NumberOfYears: {NumberOfYears}", SummaryColumns = new ObservableCollection<ISummaryColumn>() { new GridSummaryColumn() { Name = "SalesAmount", MappingName="Total", SummaryType= SummaryType.Int32Aggregate, Format="{Sum:c}" } , new GridSummaryColumn() { Name = "NumberOfYears", MappingName="Year", SummaryType= SummaryType.CountAggregate, Format="{Count:d}" } } }; } private void addColumn_Click(object sender, RoutedEventArgs e) { this.dataGrid.CaptionSummaryRow.SummaryColumns.Add(new GridSummaryColumn() { Name = "Q1Sales", MappingName = "QS1", SummaryType = SummaryType.Int32Aggregate, Format = "{Sum:d}" }); this.dataGrid.CaptionSummaryRow.Title = "Total Sales: {SalesAmount} for NumberOfYears: {NumberOfYears} and Quaterly Sales is {Q1Sales}"; this.dataGrid.View.CaptionSummaryRow = this.dataGrid.CaptionSummaryRow; this.dataGrid.RowGenerator.Items.ForEach(o => { if (o.RowType == RowType.CaptionCoveredRow || o.RowType == RowType.CaptionRow) o.GetType().GetProperty("RowIndex").SetValue(o, -1); }); this.dataGrid.GetVisualContainer().InvalidateMeasureInfo(); } View WPF DataGrid CaptionSummary Demo in GitHub.
The caption summary content and style will not be rendered in the PrintPreview dialog of WPF DataGrid (SfDataGrid). To format CaptionSummary styles in PrintPriview, a custom print manager can be inherited from GridPrintManager and the GetPrintCaptionSummaryCell method can be overridden to update the style. public class CustomPrintManagerBase : GridPrintManager { public CustomPrintManagerBase(SfDataGrid dataGrid) : base(dataGrid) { } //To Return proper cell for caption summary cells public override ContentControl GetPrintCaptionSummaryCell(object group, string mappingName) { var cell = base.GetPrintCaptionSummaryCell(group, mappingName); cell.HorizontalAlignment = HorizontalAlignment.Right; cell.HorizontalContentAlignment = HorizontalAlignment.Right; return cell; } } //To assign the custom print manager to grid when print preview is initialized at run time. dataGrid.PrintSettings.PrintManagerBase = new CustomPrintManagerBase(dataGrid); View WPF DataGrid Caption Summaries Demo in GitHub
SfDataGrid allows you, to retrieve the value of summary rows by using the SummaryCreator. GetSummaryDisplayTextForRow method when GridSummaryRow.ShowSummaryInRow is true. var summary = this.sfDataGrid.View.Records.TableSummaries[0]; var value = SummaryCreator.GetSummaryDisplayTextForRow(summary, this.sfDataGrid.View); MessageBox.Show(value); And you can also retrieve the value of each summary column by using the SummaryCreator.GetSummaryDisplayText method when GridSummaryRow.ShowSummaryInRow is false. var summary = this.sfDataGrid.View.Records.TableSummaries[0]; //Retrieves the summary row value of the Quantity column. var value = SummaryCreator.GetSummaryDisplayText(summary, "Quantity", this.sfDataGrid.View); MessageBox.Show(value); View sample in GitHub
The vertical borders is not shows for each cell in summary rows when ShowSummartInRow is disabled in WPF DataGrid (SfDataGrid). The summary rows will be displayed as shown in the following screenshot. To show the vertical borders for each cell in summary row, write style for BorderThickness of GridTableSummaryCell for GridTableSummaryRow, GridCaptionSummaryCell for CaptionSummaryRow, and GridGroupSummaryCell for GroupSummaryRow. Refer to the following code for writing style for summary cells to show the vertical border. <Style TargetType="syncfusion:GridTableSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,0"/> </Style> <Style TargetType="syncfusion:GridCaptionSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,1"/> </Style> <Style TargetType="syncfusion:GridGroupSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,1"/> </Style> When the vertical border is applied, the summary rows will be appeared as shown in the following screenshot. View WPF DataGrid Summary Demo in GitHubConclusionI hope you enjoyed learning about how to show border to column wise summaries in WPF DataGrid.You can refer to our WPF DataGrid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our WPF DataGrid example to understand how to create and manipulate data.For current customers, you can check out our WPF controls from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
The vertical borders is not shows for each cell in summary rows when ShowSummartInRow is disabled in UWP DataGrid (SfDataGrid). The summary rows will be displayed as shown in the following screenshot. To show the vertical borders for each cell in summary row, write style for BorderThickness of GridTableSummaryCell for GridTableSummaryRow, GridCaptionSummaryCell for CaptionSummaryRow, and GridGroupSummaryCell for GroupSummaryRow. Refer to the following code for writing style for summary cells to show the vertical border. <Style TargetType="syncfusion:GridTableSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,0"/> </Style> <Style TargetType="syncfusion:GridCaptionSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,1"/> </Style> <Style TargetType="syncfusion:GridGroupSummaryCell"> <Setter Property="BorderThickness" Value="0,0,1,1"/> </Style> When the vertical border is applied, the summary rows will be appeared as shown in the following screenshot. View WPF DataGrid Summary Demo in GitHubConclusionI hope you enjoyed learning about how to show border to column wise summaries.You can refer to our UWP DataGrid feature tour page to know about its other groundbreaking feature representations. You can also explore our UWP DataGrid documentation to understand how to present and manipulate data. For current customers, you can check out our UWP components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our UWP Grid and other UWP components.If you have any queries or require clarifications, please let us know in comments below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
WPF DataGrid (SfDataGrid) provides support to show the column summary. If the DataContext of SfDataGrid is ViewModel, you can bind SummaryColumns to a property in ViewModel using the AttachedProperty of type List<GridSummaryColumn>. Refer to the following code example to define the AttachedProperty of type List<GridSummaryColumn>. public class SfDataGridAttachedProperty { public static readonly DependencyProperty DynamicSummaryColumnsProperty = DependencyProperty.RegisterAttached("DynamicSummaryColumns", typeof(List<GridSummaryColumn>), typeof(SfDataGridAttachedProperty) , new FrameworkPropertyMetadata(null, OnDynamicSummaryColumnsChanged)); public static void SetDynamicSummaryColumns(UIElement element, List<GridSummaryColumn> value) { element.SetValue(DynamicSummaryColumnsProperty, value); } public static List<GridSummaryColumn> GetDynamicSummaryColumns(UIElement element) { return (List<GridSummaryColumn>)element.GetValue(DynamicSummaryColumnsProperty); } private static void OnDynamicSummaryColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { SfDataGrid grid = d as SfDataGrid; if (grid.TableSummaryRows.Count() > 1) { grid.TableSummaryRows.Clear(); } GridTableSummaryRow gsr = new GridTableSummaryRow(); gsr.ShowSummaryInRow = false; var list = ((List<GridSummaryColumn>)args.NewValue); foreach (var item in list) { gsr.SummaryColumns.Add(item); } grid.TableSummaryRows.Add(gsr); } } Refer to the following code example to populate GridSummaryColumn in Viewmodel. internal class ViewModel : INotifyPropertyChanged { private List<GridSummaryColumn> _summarycols; public List<GridSummaryColumn> SummaryColumns { get { return _summarycols; } set { _summarycols = value; RaisePropertyChanged("SummaryColumns"); } } public ViewModel() { PopulateEmployeeDetails(); SetSummaryColumns(); } private void SetSummaryColumns() { SummaryColumns = new List<GridSummaryColumn>(); SummaryColumns.Add(new GridSummaryColumn() { MappingName = "EmployeeID", Name = "EmployeeID", SummaryType = SummaryType.CountAggregate, Format = "Total: {Count}" }); SummaryColumns.Add(new GridSummaryColumn() { MappingName = "EmployeeSalary", Name = "EmployeeSalary", SummaryType = SummaryType.DoubleAggregate, Format = "Total: {Sum}" }); } } Refer to the following code example to bind the attached property in SfDataGrid. <Syncfusion:SfDataGrid x:Name="sfdatagrid" local:SfDataGridAttachedProperty.DynamicSummaryColumns="{Binding SummaryColumns}" ItemsSource="{Binding EmployeeDetails}"> </Syncfusion:SfDataGrid> View WPF DataGrid Summaries Demo in GitHub.
tWPF DataGrid (SfDataGrid) provides support to show the column summary. If the DataContext of SfDataGrid is ViewModel, you can bind SummaryColumns to a property in ViewModel using the AttachedProperty of type List<GridSummaryColumn>. Refer to the following code example to define the AttachedProperty of type List<GridSummaryColumn>. public class SfDataGridAttachedProperty { public static readonly DependencyProperty DynamicSummaryColumnsProperty = DependencyProperty.RegisterAttached("DynamicSummaryColumns", typeof(List<GridSummaryColumn>), typeof(SfDataGridAttachedProperty) , new FrameworkPropertyMetadata(null, OnDynamicSummaryColumnsChanged)); public static void SetDynamicSummaryColumns(UIElement element, List<GridSummaryColumn> value) { element.SetValue(DynamicSummaryColumnsProperty, value); } public static List<GridSummaryColumn> GetDynamicSummaryColumns(UIElement element) { return (List<GridSummaryColumn>)element.GetValue(DynamicSummaryColumnsProperty); } private static void OnDynamicSummaryColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) { SfDataGrid grid = d as SfDataGrid; if (grid.TableSummaryRows.Count() > 1) { grid.TableSummaryRows.Clear(); } GridTableSummaryRow gsr = new GridTableSummaryRow(); gsr.ShowSummaryInRow = false; var list = ((List<GridSummaryColumn>)args.NewValue); foreach (var item in list) { gsr.SummaryColumns.Add(item); } grid.TableSummaryRows.Add(gsr); } } Refer to the following code example to populate GridSummaryColumn in Viewmodel. internal class ViewModel : INotifyPropertyChanged { private List<GridSummaryColumn> _summarycols; public List<GridSummaryColumn> SummaryColumns { get { return _summarycols; } set { _summarycols = value; RaisePropertyChanged("SummaryColumns"); } } public ViewModel() { PopulateEmployeeDetails(); SetSummaryColumns(); } private void SetSummaryColumns() { SummaryColumns = new List<GridSummaryColumn>(); SummaryColumns.Add(new GridSummaryColumn() { MappingName = "EmployeeID", Name = "EmployeeID", SummaryType = SummaryType.CountAggregate, Format = "Total: {Count}" }); SummaryColumns.Add(new GridSummaryColumn() { MappingName = "EmployeeSalary", Name = "EmployeeSalary", SummaryType = SummaryType.DoubleAggregate, Format = "Total: {Sum}" }); } } Refer to the following code example to bind the attached property in SfDataGrid. <Syncfusion:SfDataGrid x:Name="sfdatagrid" local:SfDataGridAttachedProperty.DynamicSummaryColumns="{Binding SummaryColumns}" ItemsSource="{Binding EmployeeDetails}"> </Syncfusion:SfDataGrid> View WPF DataGrid Summaries Demo in GitHub.ConclusionI hope you enjoyed learning about how to define summary rows using attached property in WPF DataGrid.You can refer to our WPF DataGridWPF DataGrid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our WPF DataGrid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Show the total summary value in DateTime format You can implement your own summary aggregate functions using the GridSummaryColumn.CustomAggregate property when built-in aggregate functions do not meet your requirement. The summary value can be calculated based on any custom logic. In the following example, the Time column of data grid displays time in minutes. The custom summary aggregate for the summary column is created to display the total time in HH:MM format. C# public Form2() { InitializeComponent(); this.sfDataGrid.DataSource = this.CreateTable(); this.sfDataGrid.TableSummaryRows.Add(new GridTableSummaryRow() { Name = "tableSumamryTrue", ShowSummaryInRow = false, Title = "Total : {TotalTime}", SummaryColumns = new System.Collections.ObjectModel.ObservableCollection<Syncfusion.Data.ISummaryColumn>() { new GridSummaryColumn() { Name = "TotalTime", CustomAggregate=new CustomSummary(), SummaryType=SummaryType.Custom, Format="Total time : {TotalHours}", MappingName="Time in minutes" }, } }); } public class CustomSummary : ISummaryAggregate { public CustomSummary() { } private string totalHours; public string TotalHours { get { return totalHours; } set { totalHours = value; } } public Action<IEnumerable, string, PropertyDescriptor> CalculateAggregateFunc() { return (items, property, pd) => { var enumerableItems = items as IEnumerable<SalesByYear>; //To check the summary format of the summary row. if (pd.Name == "TotalHours") { int total = 0; foreach (var item in items) { DataRowView dr = item as DataRowView; total += int.Parse(dr["Time in minutes"].ToString()); } this.totalHours = total / 60 + " Hours : " + total % 60 + " minutes"; } }; } } VB Public Sub New() InitializeComponent() Me.sfDataGrid.DataSource = Me.CreateTable() Me.sfDataGrid.TableSummaryRows.Add(New GridTableSummaryRow() With {.Name = "tableSumamryTrue", .ShowSummaryInRow = False, .Title = "Total : {TotalTime}", .SummaryColumns = New System.Collections.ObjectModel.ObservableCollection(Of Syncfusion.Data.ISummaryColumn) (New Syncfusion.Data.ISummaryColumn() {New GridSummaryColumn() With {.Name = "TotalTime", .CustomAggregate = New CustomSummary(), .SummaryType=SummaryType.Custom, .Format="Total time : {TotalHours}", .MappingName="Time in minutes"}})}) End Sub Public Class CustomSummary Implements ISummaryAggregate Public Sub New() End Sub Private _totalHours As String Public Property TotalHours() As String Get Return _totalHours End Get Set(ByVal value As String) _totalHours = value End Set End Property Public Function CalculateAggregateFunc() As Action(Of IEnumerable, String, PropertyDescriptor) Implements ISummaryAggregate.CalculateAggregateFunc Return Sub(items, [property], pd) If pd.Name = "TotalHours" Then Dim total As Integer = 0 For Each item In items Dim dr As DataRowView = TryCast(item, DataRowView) total += Integer.Parse(dr("Time in minutes").ToString()) Next item Me._totalHours = total \ 60 & " Hours : " & total Mod 60 & " minutes" End If End Sub End Function End Class Sample: How to show the total hours and minutes of DateTime column in summary row using custom aggregate
Summaries By default, the GridGroupingControl does not have support to freeze a summary row. To achieve place a single row at the bottom of the grid and set the calculated summary values to that grid cell which acts as a summary row. GridControl customization CS public class EngineSummaryGrid { private GridControl grid; private GridGroupingControl parentGrid; public void WiredSummary(GridGroupingControl ggc) { parentGrid = ggc; parentGrid.TopLevelGroupOptions.ShowSummaries = false; parentGrid.TableModel.QueryColWidth += TableModel_QueryColWidth; parentGrid.TableControl.Layout += TableControl_Layout; //Initializing the grid with single row. grid = new GridControl(); grid.ThemesEnabled = true; grid.Model.Options.NumberedRowHeaders = false; grid.Model.RowCount = 1; this.grid.Model.ColCount = this.parentGrid.TableDescriptor.Columns.Count; grid.Properties.ColHeaders = false; ggc.TableControl.Controls.Add(grid); SetSummary(ggc); } private void TableModel_QueryColWidth(object sender, GridRowColSizeEventArgs e) { this.grid.Model.ColWidths[e.Index] = e.Size; } private void TableControl_Layout(object sender, LayoutEventArgs e) { SummaryRowSize(); } private void SummaryRowSize() { parentGrid.TableControl.ResetGridBounds(); this.parentGrid.TableControl.ResetGridBounds(); this.parentGrid.TableControl.GridBounds = new Rectangle(this.parentGrid.TableControl.GridBounds.X, this.parentGrid.TableControl.GridBounds.Y, this.parentGrid.TableControl.GridBounds.Width, this.parentGrid.TableControl.GridBounds.Height - (this.parentGrid.TableControl.DefaultRowHeight)); int height = this.parentGrid.TableControl.GridBounds.Height + this.parentGrid.TableControl.DefaultRowHeight; this.grid.Location = new Point(0, height - this.parentGrid.TableControl.DefaultRowHeight); this.grid.Size = new Size(this.parentGrid.TableControl.ClientSize.Width, this.parentGrid.TableControl.DefaultRowHeight); } } VB Public Class EngineSummaryGrid Private grid As GridControl Private parentGrid As GridGroupingControl Public Sub WiredSummary(ByVal ggc As GridGroupingControl) parentGrid = ggc parentGrid.TopLevelGroupOptions.ShowSummaries = False AddHandler parentGrid.TableModel.QueryColWidth, AddressOf TableModel_QueryColWidth AddHandler parentGrid.TableControl.Layout, AddressOf TableControl_Layout 'Initializing the grid with single row. grid = New GridControl() grid.ThemesEnabled = True grid.Model.Options.NumberedRowHeaders = False grid.Model.RowCount = 1 Me.grid.Model.ColCount = Me.parentGrid.TableDescriptor.Columns.Count grid.Properties.ColHeaders = False ggc.TableControl.Controls.Add(grid) SetSummary(ggc) End Sub Private Sub TableModel_QueryColWidth(ByVal sender As Object, ByVal e As GridRowColSizeEventArgs) Me.grid.Model.ColWidths(e.Index) = e.Size End Sub Private Sub TableControl_Layout(ByVal sender As Object, ByVal e As LayoutEventArgs) SummaryRowSize() End Sub Private Sub SummaryRowSize() parentGrid.TableControl.ResetGridBounds() Me.parentGrid.TableControl.ResetGridBounds() Me.parentGrid.TableControl.GridBounds = New Rectangle(Me.parentGrid.TableControl.GridBounds.X, Me.parentGrid.TableControl.GridBounds.Y, Me.parentGrid.TableControl.GridBounds.Width, Me.parentGrid.TableControl.GridBounds.Height - (Me.parentGrid.TableControl.DefaultRowHeight)) Dim height As Integer = Me.parentGrid.TableControl.GridBounds.Height + Me.parentGrid.TableControl.DefaultRowHeight Me.grid.Location = New Point(0, height - Me.parentGrid.TableControl.DefaultRowHeight) Me.grid.Size = New Size(Me.parentGrid.TableControl.ClientSize.Width, Me.parentGrid.TableControl.DefaultRowHeight) End Sub End Class Setting the Summary value to GridControl CS private void SetSummary(GridGroupingControl ggc) { for (int j = 0; j < grid.Model.ColCount; j++) { GridSummaryRowDescriptor row = ggc.TableDescriptor.SummaryRows[0]; GridSummaryColumnDescriptor scd = row.GetSummaryColumnAtCol(j); if (scd != null) { string text = scd.GetDisplayText(ggc.Engine.Table.DisplayElements[0].ParentGroup); grid.Model[1, j].CellValue = row.Title; grid.Model[1, j + 1].CellValue = text; grid.Model[1, j + 1].Enabled = false; } } } VB Private Sub SetSummary(ByVal ggc As GridGroupingControl) For j As Integer = 0 To grid.Model.ColCount - 1 Dim row As GridSummaryRowDescriptor = ggc.TableDescriptor.SummaryRows(0) Dim scd As GridSummaryColumnDescriptor = row.GetSummaryColumnAtCol(j) If scd IsNot Nothing Then Dim text As String = scd.GetDisplayText(ggc.Engine.Table.DisplayElements(0).ParentGroup) grid.Model(1, j).CellValue = row.Title grid.Model(1, j + 1).CellValue = text grid.Model(1, j + 1).Enabled = False End If Next j End Sub Adding customized grid to GridGroupingControl CS //To add the summary row grid to GridGrouping control SummaryGrid = new EngineSummaryGrid(); SummaryGrid.WiredSummary(this.gridGroupingControl1); VB 'To add the summary row grid to GridGrouping control SummaryGrid = New EngineSummaryGrid() SummaryGrid.WiredSummary(Me.gridGroupingControl1) Screenshot Note:By this solution, the summary values will not be updated when modifying records in the grid. Samples: C#: Freezing SummaryRow_CS VB: Freezing SummaryRow_VB Reference link: https://help.syncfusion.com/windowsforms/gridgrouping/summaries
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column.ConclusionI hope you enjoyed learning about how to get aggregate WebApiAdaptor enabled in ASP.NET MVC Grid.You can refer to our ASP.NET MVC Grid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our ASP.NET MVC Grid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column.Note:A new version of Essential Studio for ASP.NET is available. Versions prior to the release of Essential Studio 2014, Volume 2 will now be referred to as a classic versions.The new ASP.NET suite is powered by Essential Studio for JavaScript providing client-side rendering of HTML 5-JavaScript controls, offering better performance, and better support for touch interactivity. The new version includes all the features of the old version, so migration is easy.The Classic controls can be used in existing projects; however, if you are starting a new project, we recommend using the latest version of Essential Studio for ASP.NET. Although Syncfusion will continue to support all Classic Versions, we are happy to assist you in migrating to the newest edition.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls. If you have any queries or require clarifications, please let us know in the comments section below.You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Usually, remote data handlers like WebAPIAdaptor, return only the current page records which is the default behavior. So, we can summarize the current page records only in the Grid Summary Footer. The concept behind this adaptor brings the records on demand which means client-end receives only the current page records. Based on the received records only this adaptor summarizes the aggregates and displays them in Grid. If we return whole records to the client-end, concept of the load on demand will be declined. Henceforth, based on the current page records the summary were displayed. However, we can overcome this behavior using the custom adaptors and custom headers of the DataManager. Using the custom headers, required aggregate fields were shared to the server-end. Based on that selective fields with their records were returned to the client as aggregates along with the Items/count which will display the summary for total records. HTML: <div id="Grid"></div> JavaScript: <script type="text/javascript"> $(function () { $("#Grid").ejGrid({ dataSource: new ej.DataManager({ url: "/api/Orders", adaptor: new ej.WebApiAdaptor() }), allowPaging: true, showSummary: true, summaryRows: [ { title: "Sum", summaryColumns: [ { summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" } ] } ], load: "onLoad", actionBegin: "onActionBegin", columns: [ { field: "OrderID", headerText: "Order ID", textAlign: ej.TextAlign.Right }, { field: "CustomerID", headerText: "Customer ID" }, { field: "EmployeeID", headerText: "Employee ID", textAlign: ej.TextAlign.Right }, { field: "Freight", format: "{0:C3}", textAlign: ej.TextAlign.Right }, { field: "ShipCity", headerText: "Ship City" } ] }); }); </script> Razor: @(Html.EJ().Grid<object>("Grid") .AllowPaging() .Datasource(ds => { ds.URL("/api/Orders"); ds.Adaptor(AdaptorType.WebApiAdaptor); }) .ShowSummary() .SummaryRow(row => { row.Title("Sum") .SummaryColumns(col => { col.SummaryType(SummaryType.Sum) .Format("{0:C3}") .DisplayColumn("Freight") .DataMember("Freight").Add(); }).Add(); }) .ClientSideEvents(events => { events.ActionBegin("onActionBegin"); events.Load("onLoad"); }) .Columns(col => { col.Field("OrderID").HeaderText("Order ID").TextAlign(TextAlign.Right).Add(); col.Field("CustomerID").HeaderText("Customer ID").Add(); col.Field("EmployeeID").HeaderText("EmployeeID").TextAlign(TextAlign.Right).Add(); col.Field("Freight").Format("{0:C3}").TextAlign(TextAlign.Right).Add(); col.Field("ShipCity").HeaderText("Ship City").Add(); }) ) WebForms: <ej:Grid id="Grid" runat="server" ShowSummary="true" Allowpaging="true"> <EditSettings AllowEditing="True" AllowAdding="True" AllowDeleting="True" EditMode="Batch"></EditSettings> <ToolbarSettings ShowToolbar="True" ToolbarItems="add,edit,delete,update,cancel"></ToolbarSettings> <Columns> <ej:Column Field="OrderID" HeaderText="Order ID" IsPrimaryKey="true" TextAlign="Right" /> <ej:Column Field="CustomerID" HeaderText="Customer ID" /> <ej:Column Field="EmployeeID" HeaderText="Employee ID" TextAlign="Right" /> <ej:Column Field="Freight" Format ="{0:C3}" TextAlign="Right"/> <ej:Column Field="ShipCity" HeaderText="Ship City"/> </Columns> <SummaryRows> <ej:SummaryRow Title="Sum"> <SummaryColumn> <ej:SummaryColumn SummaryType="Sum" Format="{0:C3}" DisplayColumn="Freight" DataMember="Freight" /> </SummaryColumn> </ej:SummaryRow> </SummaryRows> <ClientSideEvents Load="onLoad" ActionBegin="onActionBegin" /> </ej:Grid> .Net Core <ej-grid id="Grid" allow-paging="true" load="onLoad" show-summary="true" action-begin="onActionBegin"> <e-datamanager url="/api/Orders" adaptor="WebApiAdaptor" /> <e-summary-rows> <e-summary-row title="Sum"> <e-summary-columns> <e-summary-column summary-type="Sum" format="{0:C3}" display-column="Freight" datamember="Freight" /> </e-summary-columns> </e-summary-row> </e-summary-rows> <e-columns> <e-column field="OrderID" header-text="Order ID" is-primary-key="true" text-align="Right"></e-column> <e-column field="EmployeeID" header-text="Employee ID" text-align="Right"></e-column> <e-column field="CustomerID" header-text="Customer ID"></e-column> <e-column field="Freight" text-align="Right" format="{0:C3}"></e-column> <e-column field="ShipCity" header-text="Ship City"> </e-column> </e-columns> </ej-grid> Angular2: <ej-grid id="Grid" #grid [allowPaging]="true" [showSummary]="true" [summaryRows]="summaryrows" [dataSource]="datasrc" (load)="onLoad($event)" (actionBegin)="onActionBegin($event)"> <e-columns> <e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="right"></e-column> <e-column field="CustomerID" headerText="Customer ID"></e-column> <e-column field="EmployeeID" headerText="Employee Name" textAlign="right"></e-column> <e-column field="Freight" format="{0:C3}" textAlign="right"></e-column> <e-column field="ShipCity" headerText="Ship City"></e-column> </e-columns> </ej-grid> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.datasrc = new ej.DataManager({ url: "/api/Values", adaptor: new ej.WebApiAdaptor() }) this.summaryrows = [{ title: "Sum", summaryColumns: [{ summaryType: ej.Grid.SummaryType.Sum, displayColumn: "Freight", dataMember: "Freight", format: "{0:C3}" }] }] } public datasrc: any; public summaryrows: any; } Define the Load and ActionBegin events of the Grid along with the customAdaptor. In the Load event, assign the newly extended adaptor to the Grid’s dataSource. In the ActionBegin event, lookup the model.query for aggregates and push them to the custom headers of the dataSource, an ej.DataManager instance. <script> var customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData;; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej.aggregates[agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); function onLoad(args) { this.model.dataSource.adaptor = new customAdaptor(); } function onActionBegin(args) { var rows = this.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } this.model.dataSource.dataSource.headers = []; this.model.dataSource.dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } </script> TypeScript: import { Component, OnInit, Input, ElementRef, ViewChild } from '@angular/core'; import { EJComponents } from "ej-angular2/src/ej/core"; @Component({ selector: 'ej-app', templateUrl: 'src/grid/grid.component.html', }) export class GridComponent { constructor() { this.customAdaptor = new ej.WebApiAdaptor().extend({ processResponse: function (data, ds, query, xhr, request, changes) { var resultdata = data, pvt = request && request.ejPvtData; var result = this.base.processResponse.apply(this, [data, ds, query, xhr, request, changes]); if (pvt && pvt.aggregates && pvt.aggregates.length) { var agg = pvt.aggregates, args = {}, fn, res = {}; for (var i = 0; i < agg.length; i++) { fn = ej["aggregates"][agg[i].type]; if (fn) res[agg[i].field + " - " + agg[i].type] = fn(resultdata.aggregate, agg[i].field); } result.aggregates = res; } return result; } }); } public customAdaptor: any; onLoad(args) { args.model.dataSource().adaptor = new this.customAdaptor; } onActionBegin(args) { var rows = args.model.summaryRows, scolumns, sCol = [], aggregate = []; for (var row = 0, rlen = rows.length; row < rlen; row++) { scolumns = rows[row].summaryColumns; for (var col = 0, clen = scolumns.length; col < clen; col++) { aggregate.push(scolumns[col].dataMember); } } args.model.dataSource().dataSource.headers = []; args.model.dataSource().dataSource.headers.push({ aggregates: JSON.stringify(aggregate) }); } } In the server-end, retrieve the pushed aggregated values and deserialize them to List<string>. Use the deserialized object as input for DataOperations for selecting the aggregate columns. Later, return them to the client-end along with the Items/Count wrapped object. Web API Controller: public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { var queryString = HttpContext.Current.Request.QueryString; string agg = Request.Headers.GetValues("aggregates").ToList()[0]; int skip = Convert.ToInt32(queryString["$skip"]); int take = Convert.ToInt32(queryString["$top"]); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Asp.Net core WebApi controller public class OrdersController : ApiController { NorthwindDataContext db = new NorthwindDataContext(); public object Get() { string agg = Request.Headers["aggregates"].ToString(); int skip = Convert.ToInt32(Request.Query.ToList()[1].Value.ToString()); int take = Convert.ToInt32(Request.Query.ToList()[2].Value.ToString()); List<string> aggregates = (List<string>)JsonConvert.DeserializeObject(agg, typeof(List<string>)); IEnumerable<OrdersView> order = db.OrdersViews.ToList(); DataOperations ds = new DataOperations(); List<string> str = new List<string>(); IEnumerable aggregate = ds.PerformSelect(order, aggregates); return new { Items = order.Skip(skip).Take(take), Count = order.Count(), aggregate = aggregate }; } } Note: To avoid the serialization error only, WebApiAdaptor is prevented the default aggregate records returning from server-end. But this KB, proposed a way to generate aggregate for total records. It may lead to the serialization error in the case larger record count. Figure. Grid with summation of total records for Freight Column. ConclusionI hope you enjoyed learning about how can I obtain a grid with aggregate WebApiAdaptor enabled?You can refer to our ASP.NET Core Grid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our ASP.NET Core Grid example to understand how to create and manipulate data.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
You can add a text box control to each group summary row of WPF DataGrid (SfDataGrid) by overriding the style of GroupSummaryRowControl. In the sample, a text box with some text has been added to each group summary row of SfDataGrid. Refer to the following code snippet to load the text box control to each group summary row. XAML <Window.Resources> <local:GroupSummaryConverter x:Key="converter"/> <Style TargetType="{x:Type syncfusion:GroupSummaryRowControl}"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="Gray"/> <Setter Property="FontSize" Value="14"/> <Setter Property="FontWeight" Value="Normal"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="IsTabStop" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type syncfusion:GroupSummaryRowControl}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="BorderStates"> <VisualState x:Name="NormalRow"/> <VisualState x:Name="FrozenRow"> <Storyboard BeginTime="0"> <ThicknessAnimationUsingKeyFrames BeginTime="0" Duration="1.0:0:0" Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="PART_GroupSummaryRowBorder"> <EasingThicknessKeyFrame KeyTime="0" Value="0,0,0,1"/> </ThicknessAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="FooterRow"> <Storyboard BeginTime="0"> <ThicknessAnimationUsingKeyFrames BeginTime="0" Duration="1.0:0:0" Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="PART_GroupSummaryRowBorder"> <EasingThicknessKeyFrame KeyTime="0" Value="0,1,0,0"/> </ThicknessAnimationUsingKeyFrames> <ThicknessAnimationUsingKeyFrames BeginTime="0" Duration="1.0:0:0" Storyboard.TargetProperty="Margin" Storyboard.TargetName="PART_GroupSummaryRowBorder"> <EasingThicknessKeyFrame KeyTime="0" Value="0,-1,0,0"/> </ThicknessAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="PART_GroupSummaryRowBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> <Rectangle x:Name="PART_CurrentFocusRow" Margin="{TemplateBinding CurrentFocusBorderMargin}" Stroke="DarkGray" StrokeThickness="1" StrokeDashArray="2 2" Visibility="{TemplateBinding CurrentFocusRowVisibility}"/> <Border Background="{TemplateBinding GroupRowSelectionBrush}" Clip="{TemplateBinding SelectionBorderClipRect}" SnapsToDevicePixels="True" Visibility="{TemplateBinding SelectionBorderVisiblity}"> </Border> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True"> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" SnapsToDevicePixels="True" Grid.Row="0"/> </Border> <Border> <syncfusion:SfTextBoxExt Watermark="Add Remark+" Text="{Binding Path=., Converter={StaticResource converter}}" Padding="15,0,0,0" BorderThickness="1"/> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> Converter.cs This converter is used to display the text for the textbox which is present in the GroupSummaryRow. public class GroupSummaryConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var groupRecords = ((value as SummaryRecordEntry).Parent as Group).Records; var underlyingData = groupRecords[0].Data as Employee; return "The employee name of corresponding employee id (" + underlyingData.EmployeeID + ") " + "is " + underlyingData.EmployeeName; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value; } } WPF Screenshot UWP Screenshot View sample in GitHub.
Summaries In order to get the summary values of a summary row, GridEngine.GetSummaryText() method can be used. C# //Event Subscription this.gridGroupingControl1.SourceListListChangedCompleted += GridGroupingControl1_SourceListListChangedCompleted; //Event Customization private void GridGroupingControl1_SourceListListChangedCompleted(object sender, TableListChangedEventArgs e) { int row = this.gridGroupingControl1.TableModel.RowCount; var rec = this.gridGroupingControl1.Table.DisplayElements[row]; GridSummaryRow sr = rec as GridSummaryRow; if (sr != null) { foreach (GridSummaryColumnDescriptor scd in sr.SummaryRowDescriptor.SummaryColumns) { string result = GridEngine.GetSummaryText(sr.ParentGroup, scd); this.textBox1.Text = result; } } } VB 'Event Subscription AddHandler Me.gridGroupingControl1.SourceListListChangedCompleted, AddressOf GridGroupingControl1_SourceListListChangedCompleted 'Event Customization Private Sub GridGroupingControl1_SourceListListChangedCompleted(ByVal sender As Object, ByVal e As TableListChangedEventArgs) Dim row As Integer = Me.gridGroupingControl1.TableModel.RowCount Dim rec = Me.gridGroupingControl1.Table.DisplayElements(row) Dim sr As GridSummaryRow = TryCast(rec, GridSummaryRow) If sr IsNot Nothing Then For Each scd As GridSummaryColumnDescriptor In sr.SummaryRowDescriptor.SummaryColumns Dim result As String = GridEngine.GetSummaryText(sr.ParentGroup, scd) Me.textBox1.Text = result Next scd End If End Sub Screenshot Samples: C#: Get summary values_CS VB: Get summary values_VB Reference link: https://help.syncfusion.com/windowsforms/gridgrouping/summaries
Summaries In order to show the summary value in group caption in WinForms GridGroupingControl, customize the caption text format with name of GridSummaryRowDescriptor and name of GridSummaryColumnDescriptor. C# //To add summary. GridSummaryColumnDescriptor summaryColumnDescriptor = new GridSummaryColumnDescriptor(); summaryColumnDescriptor.Name = "Category"; summaryColumnDescriptor.DataMember = "CategoryID"; summaryColumnDescriptor.Format = "{Average:#.00}"; summaryColumnDescriptor.SummaryType = SummaryType.DoubleAggregate; GridSummaryRowDescriptor summaryRowDescriptor = new GridSummaryRowDescriptor(); summaryRowDescriptor.Name = "Average of CategoryID column"; summaryRowDescriptor.SummaryColumns.Add(summaryColumnDescriptor); gridGroupingControl1.TableDescriptor.SummaryRows.Add(summaryRowDescriptor); this.gridGroupingControl1.TopLevelGroupOptions.ShowSummaries = false; //To retrieve summaryrow name. string summaryRowName = summaryRowDescriptor.Name; //To retrieve summarycolumn name. string summaryColumnName = summaryColumnDescriptor.Name; //Setting caption text. this.gridGroupingControl1.ChildGroupOptions.CaptionText = "{Category} {RecordCount} Items at Average {" + summaryRowName + "." + summaryColumnName + "}" ; VB 'To add summary. Dim summaryColumnDesecriptor As New GridSummaryColumnDescriptor() summaryColumnDesecriptor.Name = "Category" summaryColumnDesecriptor.DataMember = "CategoryID" summaryColumnDesecriptor.Format = "{Average:#.00}" summaryColumnDesecriptor.SummaryType = SummaryType.DoubleAggregate Dim summaryRowDescriptor As New GridSummaryRowDescriptor() summaryRowDescriptor .Name = "Summary Row" summaryRowDescriptor .SummaryColumns.Add(summaryColumnDescriptor) gridGroupingControl1.TableDescriptor.SummaryRows.Add(summaryRowDescriptor) Me.gridGroupingControl1.TopLevelGroupOptions.ShowSummaries = False 'To retrieve summaryrow name. Dim summaryRowName As String = summaryRowDescriptor.Name 'To retrieve summarycolumn name. Dim summaryColumnName As String = summaryColumnDescriptor.Name 'Setting caption text. Me.gridGroupingControl1.ChildGroupOptions.CaptionText = "{Category} {RecordCount} Items at Average {" & summaryRowName & "." & summaryColumnName & "}" Screenshot Samples:C#: Retrieving SummaryValue_CSVB: Retrieving SummaryValue_VBReference link: https://help.syncfusion.com/windowsforms/gridgrouping/summariesConclusionI hope you enjoyed learning about how to show the summary value of a summary row in caption row in WinForms GridGroupingControl.You can refer to our WinForms GridGroupingControl’s feature tour page to know about its other groundbreaking feature representations. You can also explore our WinForms GridGroupingControl documentation to understand how to present and manipulate data.For current customers, you can check out our WinForms components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our WinForms GridGroupingControl and other WinForms components.If you have any queries or require clarifications, please let us know in comments below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Custom summaries By default, the summary values will be added for the entire column. In order to add the summary values based on another column, a custom summary class can be created by implementing the SummaryBase. In the custom summary class, the Combine() method can be used/created to get the updated summary values based on another column values. In the provided sample, the summary value of “SummaryData” column will be calculated based on the checked records. C# //Triggering event for CustomSummary. this.gridGroupingControl1.TableDescriptor.QueryCustomSummary += new GridQueryCustomSummaryEventHandler(gridGroupingControl1_QueryCustomSummary); //"SummaryData" is summary column and "includeSummary" is condition column. //Include summary for Checked records. GridSummaryColumnDescriptor sumColumn = GetSumSummaryColumnDescriptor("SummaryData", "IncludeSummary"); GridSummaryRowDescriptor rowDescriptor = new GridSummaryRowDescriptor("Row0", "Summary of Checked records only", sumColumn); rowDescriptor.TitleColumnCount = 2; //Adding summary row to the table descriptor this.gridGroupingControl1.TableDescriptor.SummaryRows.Add(rowDescriptor); //Event customization for CustomSummary private void gridGroupingControl1_QueryCustomSummary(object sender, GridQueryCustomSummaryEventArgs e) { //checking for custom summary. if (e.SummaryDescriptor.SummaryType == SummaryType.Custom) { //Sets the custom summary method for custom calculations. e.SummaryDescriptor.CreateSummaryMethod = new CreateSummaryDelegate(CustomSummary.CreateSummaryMethod); } e.Handled = true; } //CustomSummary class public sealed class CustomSummary : SummaryBase { public CustomSummary() { } //Method for custom summary calculation. public static ISummary CreateSummaryMethod(SummaryDescriptor sd, Record record) { object obj = sd.GetValue(record); bool isNull = (obj == null || obj is DBNull); if (isNull) { return Empty; } else { int i = sd.Name.LastIndexOf('_') + 1; string conditionColumn = sd.Name.Substring(i); object obj1 = record.GetValue(conditionColumn); if (obj1 == null) { throw new ArgumentException(string.Format("[{0}] not a column.", conditionColumn)); } //DefaultValue of summary if unchecked. int sumValue = 0; if (record.GetValue(conditionColumn).ToString() == "True") //Summary value of record if it is checked. sumValue = Convert.ToInt32(obj); return new CustomSummary(sumValue); } } } VB 'Triggering event for CustomSummary. Private Me.gridGroupingControl1.TableDescriptor.QueryCustomSummary += New GridQueryCustomSummaryEventHandler(AddressOf gridGroupingControl1_QueryCustomSummary) '"SummaryData" is summary column and "includeSummary" is condition column. 'Include summary for Checked records. Private sumColumn As GridSummaryColumnDescriptor = GetSumSummaryColumnDescriptor("SummaryData", "IncludeSummary") Private rowDescriptor As New GridSummaryRowDescriptor("Row0", "Summary of Checked records only", sumColumn) rowDescriptor.TitleColumnCount = 2 'Adding summary row to the table descriptor Me.gridGroupingControl1.TableDescriptor.SummaryRows.Add(rowDescriptor) 'Event customization for CustomSummary private void gridGroupingControl1_QueryCustomSummary(Object sender, GridQueryCustomSummaryEventArgs e) 'checking for custom summary. If e.SummaryDescriptor.SummaryType = SummaryType.Custom Then 'Sets the custom summary method for custom calculations. e.SummaryDescriptor.CreateSummaryMethod = New CreateSummaryDelegate(CustomSummary.CreateSummaryMethod) End If e.Handled = True 'CustomSummary class Public NotInheritable Class CustomSummary Inherits SummaryBase Public Sub New() End Sub 'Method for custom summary calculation. public Shared Function ISummary CreateSummaryMethod(SummaryDescriptor sd, Record record) Dim obj As Object = sd.GetValue(record) Dim isNull As Boolean = (obj Is Nothing OrElse TypeOf obj Is DBNull) If isNull Then Return Empty Else Dim i As Integer = sd.Name.LastIndexOf("_"c) + 1 Dim conditionColumn As String = sd.Name.Substring(i) Dim obj1 As Object = record.GetValue(conditionColumn) If obj1 Is Nothing Then Throw New ArgumentException(String.Format("[{0}] not a column.", conditionColumn)) End If 'DefaultValue of summary if unchecked. Dim sumValue As Integer = 0 If record.GetValue(conditionColumn).ToString() = "True" Then 'Summary value of record if it is checked. sumValue = Convert.ToInt32(obj) End If Return New CustomSummary(sumValue) End If End Function End Class Screenshot Samples: C#: CustomSummary_CS VB: CustomSummary_VB Reference link: https://help.syncfusion.com/windowsforms/classic/gridgroupingcontrol/summaries#custom-summaries
You can load a button inside the CaptionSummaryCell by customizing the ControlTemplate of the GridCaptionSummaryCell using Style in WPF DataGrid (SfDataGrid). <Style TargetType="syncfusion:GridCaptionSummaryCell"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="syncfusion:GridCaptionSummaryCell"> <Border x:Name="PART_GridCaptionSummaryCellBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="60"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0"> <Button Content="Click" Width="50" Height="20" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type syncfusion:SfDataGrid}}, Path=DataContext.ClickCommand}" CommandParameter="{Binding}"/> </StackPanel> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> You can prevent the expanding and collapsing of the group upon clicking the button, by handling the SfDatagrid.GroupCollapsing and SfDatagrid.GroupExpanding events as shown in the below the code. public MainWindow() { InitializeComponent(); this.datagrid.GroupCollapsing += Datagrid_GroupCollapsing; this.datagrid.GroupExpanding += Datagrid_GroupExpanding; } private void Datagrid_GroupExpanding(object sender, Syncfusion.UI.Xaml.Grid.GroupChangingEventArgs e) { //Code to skip expanding the group when clicking the button in caption row. if (Mouse.DirectlyOver is Button) { e.Cancel = true; } } private void Datagrid_GroupCollapsing(object sender, Syncfusion.UI.Xaml.Grid.GroupChangingEventArgs e) { //Code to skip collapsing the group when clicking the button in caption row. if (Mouse.DirectlyOver is Button) { e.Cancel = true; } } The output upon executing the above task will be as shown below. View sample in GitHub.
Summaries By default, the title for the summary row will be added in the first column. The summary value and the title will not be added in a single cell when the datasource has single column. In order to display the SummaryValue with its title, the Style property of GridColumnDescriptor can be set as GridSummaryStyle.FillRow and set the respective format of the summary value with title by using Format property. C# //To add the summary for a column summaryColumnDescriptor = new GridSummaryColumnDescriptor("TotalSum"); summaryColumnDescriptor.SummaryType = SummaryType.Int32Aggregate; summaryColumnDescriptor.Format = "Total summary: {Sum}"; summaryColumnDescriptor.DataMember = "CategoryID"; summaryColumnDescriptor.Style = GridSummaryStyle.FillRow; GridSummaryRowDescriptor summaryRowDescriptor = new GridSummaryRowDescriptor(); //To add summary columns to summary row summaryRowDescriptor.SummaryColumns.Add(summaryColumnDescriptor); //To add summary row to the TableDescriptor this.gridGroupingControl1.TableDescriptor.SummaryRows.Add(summaryRowDescriptor); VB 'To add the summary for a column summaryColumnDescriptor = New GridSummaryColumnDescriptor("TotalSum") summaryColumnDescriptor.SummaryType = SummaryType.Int32Aggregate summaryColumnDescriptor.Format = "Total summary: {Sum}" summaryColumnDescriptor.DataMember = "CategoryID" summaryColumnDescriptor.Style = GridSummaryStyle.FillRow Dim summaryRowDescriptor As New GridSummaryRowDescriptor() 'To add summary columns to summary row summaryRowDescriptor.SummaryColumns.Add(summaryColumnDescriptor) 'To add summary row to the TableDescriptor Me.gridGroupingControl1.TableDescriptor.SummaryRows.Add(summaryRowDescriptor) Screenshot Samples: C#: SummaryWithTitle_CS VB: SummaryWithTitle_VB Reference link: https://help.syncfusion.com/windowsforms/gridgrouping/summaries
SfDataGrid supports setting custom GroupCaptionTextFormat for CaptionSummaryRows. By default the group caption text will be in the format "{ColumnName} : {Key} - {ItemsCount} Items". You can customize this text format by setting the SfDataGrid.GroupCaptionTextFormat property. Refer the below code example which illustrates how to customize the group caption text in SfDataGrid. SfDataGrid dataGrid = new SfDataGrid(); //Customized group caption text in German. dataGrid.GroupCaptionTextFormat = "{ColumnName} : {Key} - {ItemsCount} Produkte"; ConclusionI hope you enjoyed learning about how to customize GroupCaptionTextFormat in DataGrid.You can refer to our Xamarin.Forms DataGrid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
Summaries In order to show the sum of the two columns value in the summary, custom summary can be used to customize the summary values. To create the custom summary, you can use the SummaryType.Custom option for summary row descriptor. The custom summary can be created by deriving the SummaryBase class and override the methods of it. For more information about the custom summary, refer this link. C# //Sum of col2 and Col3 GridSummaryColumnDescriptor sumCol2 = GetSumSummaryColumnDescriptor("SampleData1", "SampleData2"); GridSummaryRowDescriptor rowDescriptor = new GridSummaryRowDescriptor("Row0", "Sum of SampleData1 and SampleData2 columns", new GridSummaryColumnDescriptor[] { sumCol2 }); this.gridGroupingControl1.TableDescriptor.SummaryRows.Add(rowDescriptor); /// <summary> /// Creating a CustomSummaary method. /// </summary> private void gridGroupingControl1_QueryCustomSummary(object sender, GridQueryCustomSummaryEventArgs e) { if (e.SummaryDescriptor.SummaryType == SummaryType.Custom) { e.SummaryDescriptor.CreateSummaryMethod = new CreateSummaryDelegate(CustomSummary.CreateSummaryMethod); } e.Handled = true; } /// <summary> /// Applying WeightedSummary for Given Columns /// </summary> private GridSummaryColumnDescriptor GetSumSummaryColumnDescriptor(string col1, string col2) { GridSummaryColumnDescriptor col2Summary = new GridSummaryColumnDescriptor(); col2Summary.Name = string.Format("{0}_{1}", col1, col2); //special name following the convention above col2Summary.DataMember = col1; //the column this summary is applied to col2Summary.DisplayColumn = col1; //where this summary is displayed col2Summary.Format = "{TotalSummary:#.##}"; //what is displayed in the summary col2Summary.SummaryType = SummaryType.Custom; //marks this as a CustomSummary col2Summary.Appearance.AnySummaryCell.HorizontalAlignment = GridHorizontalAlignment.Right; col2Summary.MaxLength = 6; return col2Summary; } VB 'Sum of col2 and Col3 Private sumCol2 As GridSummaryColumnDescriptor = GetSumSummaryColumnDescriptor("SampleData1", "SampleData2") Private rowDescriptor As New GridSummaryRowDescriptor("Row0", "Sum of SampleData1 and SampleData2 columns", New GridSummaryColumnDescriptor() { sumCol2 }) Me.gridGroupingControl1.TableDescriptor.SummaryRows.Add(rowDescriptor) ''' <summary> ''' Creating a CustomSummaary method. ''' </summary> private void gridGroupingControl1_QueryCustomSummary(Object sender, GridQueryCustomSummaryEventArgs e) If e.SummaryDescriptor.SummaryType = SummaryType.Custom Then e.SummaryDescriptor.CreateSummaryMethod = New CreateSummaryDelegate(AddressOf CustomSummary.CreateSummaryMethod) End If e.Handled = True ''' <summary> ''' Applying WeightedSummary for Given Columns ''' </summary> private GridSummaryColumnDescriptor GetSumSummaryColumnDescriptor(String col1, String col2) Dim col2Summary As New GridSummaryColumnDescriptor() col2Summary.Name = String.Format("{0}_{1}", col1, col2) 'special name following the convention above col2Summary.DataMember = col1 'the column this summary is applied to col2Summary.DisplayColumn = col1 'where this summary is displayed col2Summary.Format = "{TotalSummary:#.##}" 'what is displayed in the summary col2Summary.SummaryType = SummaryType.Custom 'marks this as a CustomSummary col2Summary.Appearance.AnySummaryCell.HorizontalAlignment = GridHorizontalAlignment.Right col2Summary.MaxLength = 6 Return col2Summary CustomSummary class customization C# /// <summary> /// Syncfusion Custom Summary class that computes the weighted average of the of entries /// where the weights come in from a column passed in through a naming convention. /// </summary> public sealed class CustomSummary : SummaryBase { #region "API Definition" double _valTotal; double _wgtTotal; public static readonly CustomSummary Empty = new CustomSummary(0, 0); #endregion #region Constructor public CustomSummary() { } /// <summary> /// Initializes a new summary object. /// </summary> /// <param name="valTotal"></param> /// <param name="wgtTotal"></param> public CustomSummary(double valTotal, double wgtTotal) { _wgtTotal = wgtTotal; _valTotal = valTotal; } #endregion #region CreateSummaryMethod /// <summary> /// Assign this CreateSummaryDelegate handler method to SummaryDescriptor.CreateSummaryMethod /// </summary> /// <param name="sd"></param> /// <param name="record"></param> /// <returns></returns> public static ISummary CreateSummaryMethod(SummaryDescriptor sd, Record record) { object obj = sd.GetValue(record); bool isNull = (obj == null || obj is DBNull); if (isNull) { return Empty; } else { int i = sd.Name.LastIndexOf('_') + 1; string col2 = sd.Name.Substring(i); object obj1 = record.GetValue(col2); if (obj1 == null) { throw new ArgumentException(string.Format("[{0}] not a column.", col2)); } double col2Value = Convert.ToDouble(obj1); double col1 = Convert.ToDouble(obj); return new CustomSummary(col1, col2Value); } } #endregion #region "Weighted Summary Calculation" /// <summary> /// The running weighted sum of this summary /// </summary> public double TotalSummary { get { if (_wgtTotal == 0) return _wgtTotal; return _valTotal + _wgtTotal; } } /// <summary> /// Combines this summary information with another objects summary and returns a new object. /// </summary> /// <param name="other"></param> /// <returns></returns> /// <remarks> /// This method must honor the immutable characteristics of summary objects and return /// a new summary object instead of modifying an existing summary object. /// </remarks> public override SummaryBase Combine(SummaryBase other) { return Combine((CustomSummary)other); } /// <summary> /// Combines this summary information with another objects summary and returns a new object. /// </summary> /// <remarks> /// This method must honor the immutable characteristics of summary objects and return /// a new summary object instead of modifying an existing summary object. /// </remarks> public CustomSummary Combine(CustomSummary other) { // Summary objects are immutable. That means properties cannot be modified for an // existing object. Instead every time a change is made a new object must be created (just like // System.String). return new CustomSummary(this._valTotal + other._valTotal, this._wgtTotal + other._wgtTotal); } /// <override/> public override string ToString() { return String.Format("TotalSummary = {0:0.00}", TotalSummary); } #endregion } VB ''' <summary> ''' Syncfusion Custom Summary class that computes the weighted average of the of entries ''' where the weights come in from a column passed in through a naming convention. ''' </summary> Public NotInheritable Class CustomSummary Inherits SummaryBase #region "API Definition" Private _valTotal As Double Private _wgtTotal As Double Public Shared ReadOnly Empty As New CustomSummary(0, 0) #End Region #Region "Constructor" Public Sub New() End Sub ''' <summary> ''' Initializes a new summary object. ''' </summary> ''' <param name="valTotal"></param> ''' <param name="wgtTotal"></param> Public Sub New(ByVal valTotal As Double, ByVal wgtTotal As Double) _wgtTotal = wgtTotal _valTotal = valTotal End Sub #End Region #Region "CreateSummaryMethod" ''' <summary> ''' Assign this CreateSummaryDelegate handler method to SummaryDescriptor.CreateSummaryMethod ''' </summary> ''' <param name="sd"></param> ''' <param name="record"></param> ''' <returns></returns> Public Shared Function CreateSummaryMethod(ByVal sd As SummaryDescriptor, ByVal record As Record) As ISummary Dim obj As Object = sd.GetValue(record) Dim isNull As Boolean = (obj Is Nothing OrElse TypeOf obj Is DBNull) If isNull Then Return Empty Else Dim i As Integer = sd.Name.LastIndexOf("_"c) + 1 Dim col2 As String = sd.Name.Substring(i) Dim obj1 As Object = record.GetValue(col2) If obj1 Is Nothing Then Throw New ArgumentException(String.Format("[{0}] not a column.", col2)) End If Dim col2Value As Double = Convert.ToDouble(obj1) Dim col1 As Double = Convert.ToDouble(obj) Return New CustomSummary(col1, col2Value) End If End Function #End Region #region "Weighted Summary Calculation" ''' <summary> ''' The running weighted sum of this summary ''' </summary> Public ReadOnly Property TotalSummary() As Double Get If _wgtTotal = 0 Then Return _wgtTotal End If Return _valTotal + _wgtTotal End Get End Property ''' <summary> ''' Combines this summary information with another objects summary and returns a new object. ''' </summary> ''' <param name="other"></param> ''' <returns></returns> ''' <remarks> ''' This method must honor the immutable characteristics of summary objects and return ''' a new summary object instead of modifying an existing summary object. ''' </remarks> Public Overrides Function Combine(ByVal other As SummaryBase) As SummaryBase Return Combine(CType(other, CustomSummary)) End Function ''' <summary> ''' Combines this summary information with another objects summary and returns a new object. ''' </summary> ''' <remarks> ''' This method must honor the immutable characteristics of summary objects and return ''' a new summary object instead of modifying an existing summary object. ''' </remarks> Public Function Combine(ByVal other As CustomSummary) As CustomSummary ' Summary objects are immutable. That means properties cannot be modified for an ' existing object. Instead every time a change is made a new object must be created (just like ' System.String). Return New CustomSummary(Me._valTotal + other._valTotal, Me._wgtTotal + other._wgtTotal) End Function ''' <override/> Public Overrides Function ToString() As String Return String.Format("TotalSummary = {0:0.00}", TotalSummary) End Function #End Region End Class Screenshot Samples: C#: Summary_of_Two_Columns VB: Summary_of_Two_Columns
The GridControl doesn’t support summaries by default. If you want to implement the summary row, use the “FormulaCell” cell type and set the formula to summarize the values. For example, in the below sample, the customized summary row is added in the 10th row of the GridControl. Code Snippet C# this.gridControl1.CoveredRanges.Add(GridRangeInfo.Cells(10, 4, 10, 5)); this.gridControl1.CoveredRanges.Add(GridRangeInfo.Cells(10, 1, 10, 3)); this.gridControl1[10, 4].CellType = GridCellTypeName.FormulaCell; this.gridControl1[10, 4].Text = string.Format("=Sum({0}{1}:{0}{2})", GridRangeInfo.GetAlphaLabel(1), this.gridControl1.TopRowIndex, this.gridControl1.RowCount - 1); this.gridControl1[10, 1].Text = "Total value for first column"; this.gridControl1[10, 1].Font.FontStyle = FontStyle.Bold; VB Me.gridControl1.CoveredRanges.Add(GridRangeInfo.Cells(10, 4, 10, 5)) Me.gridControl1.CoveredRanges.Add(GridRangeInfo.Cells(10, 1, 10, 3)) Me.gridControl1(10, 4).CellType = GridCellTypeName.FormulaCell Me.gridControl1(10, 4).Text = String.Format("=Sum({0}{1}:{0}{2})", GridRangeInfo.GetAlphaLabel(1), Me.gridControl1.TopRowIndex, Me.gridControl1.RowCount - 1) Me.gridControl1(10, 1).Text = "Total value for first column" Me.gridControl1(10, 1).Font.FontStyle = FontStyle.Bold Summary Row in GridControl: Sample Link: C#: SummaryRow_C# VB: SummaryRow_VB
SfDataGrid supports setting custom GroupCaptionTextFormat for CaptionSummaryRows. By default the group caption text will be in the format "{ColumnName} : {Key} - {ItemsCount} Items". You can customize this text format by setting the SfDataGrid.GroupCaptionTextFormat property. Refer the below code example which illustrates how to customize the group caption text in SfDataGrid. SfDataGrid dataGrid = new SfDataGrid(); //Customized group caption text in German. dataGrid.GroupCaptionTextFormat = "{ColumnName} : {Key} - {ItemsCount} Produkte"; ConclusionI hope you enjoyed learning about how to customize GroupCaptionTextFormat in DataGrid.You can refer to our Xamarin.iOS DataGrid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!
SfDataGrid supports setting custom GroupCaptionTextFormat for CaptionSummaryRows. By default the group caption text will be in the format "{ColumnName} : {Key} - {ItemsCount} Items". You can customize this text format by setting the SfDataGrid.GroupCaptionTextFormat property. Refer the below code example which illustrates how to customize the group caption text in SfDataGrid. SfDataGrid dataGrid = new SfDataGrid(); //Customized group caption text in German. dataGrid.GroupCaptionTextFormat = "{ColumnName} : {Key} - {ItemsCount} Produkte"; ConclusionI hope you enjoyed learning about how to customize GroupCaptionTextFormat in DataGrid?You can refer to our Xamarin.Android DataGrid feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications.For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!