Skip to main content
Question

Aggregate Total in a Non-GI custom page

  • November 10, 2025
  • 2 replies
  • 55 views

The existence of the total aggregate column in setting up a GI implies the existence of standard methods for creating a footer in a PXGrid.   This is further supported by the existence of markup for the Footer of a PXGridColumn, such as the following being valid markup:

                <Layout FooterVisible="True" />
                    <px:PXGridColumn DataField="SalesAmount" Width="95">
                        <Footer SummaryType="Sum"></Footer>
                    </px:PXGridColumn>

However, I can’t find any reliable documentation of how to leverage the GI technique in a custom page, and other questions/answers relating to this topic don’t on close inspection actually answer the topic.  For example, one of the threads suggests a solution of instead of modifying the footer to add a dummy row for the subtotal to the end of the result set - a solution that isn’t applicable to the large result sets I’m dealing with.

Can someone suggest if there is a way to replicate the GI footer subtotals in a custom page?

2 replies

darylbowman
Captain II
Forum|alt.badge.img+15

I’ve been very interested in the same question myself. Oddly enough, I noticed earlier today that as of 25 R1, the Equipment Time Cards screen (EP.30.80.00) DOES have totals on the Summary grid.

I haven’t had a chance to look at how it’s done yet, but I definitely will.


darylbowman
Captain II
Forum|alt.badge.img+15

I’m noticing a few things:

  1. The ‘Footer’ is enabled through the ‘Levels’ node:
  2. The ‘Mon’ - ‘Sun’ fields have two properties enabled: AutoCallBack, RenderEditorText (this might have to do with the PXTimeSpan)
  3. In ASPX, the grid has a databinding event configured:
    <px:PXGrid ID="gridDetails" OnRowDataBound="gridDetails_OnRowDataBound">

    And in \Pages\EP\EP308000.aspx.cs:

    protected void gridDetails_OnRowDataBound(object sender, PXGridRowEventArgs e)
    {
    ComputeTimeTotals(sender as PXGrid);
    }

    private void ComputeTimeTotals(PXGrid gridDetails)
    {
    const string timeFormat = "{0:00}:{1:00}";
    (string, string)[] fieldNames
    = { (typeof(EPEquipmentSummary.mon).Name,
    typeof(EPEquipmentTimeCard.monTotal).Name),
    (typeof(EPEquipmentSummary.tue).Name,
    typeof(EPEquipmentTimeCard.tueTotal).Name),
    (typeof(EPEquipmentSummary.wed).Name,
    typeof(EPEquipmentTimeCard.wedTotal).Name),
    (typeof(EPEquipmentSummary.thu).Name,
    typeof(EPEquipmentTimeCard.thuTotal).Name),
    (typeof(EPEquipmentSummary.fri).Name,
    typeof(EPEquipmentTimeCard.friTotal).Name),
    (typeof(EPEquipmentSummary.sat).Name,
    typeof(EPEquipmentTimeCard.satTotal).Name),
    (typeof(EPEquipmentSummary.sun).Name,
    typeof(EPEquipmentTimeCard.sunTotal).Name),
    (typeof(EPEquipmentSummary.timeSpent).Name,
    typeof(EPEquipmentTimeCard.weekTotal).Name) };

    EquipmentTimeCardMaint graph = ds.DataGraph as EquipmentTimeCardMaint;
    EPEquipmentTimeCard timeCard = graph.Document.Current;

    PXGridLevel gridLevel = gridDetails.Levels[0];
    HashSet<string> uniqueKeys = new HashSet<string>();
    Dictionary<string, PXGridColumn> footerColumns
    = gridLevel.Columns.Items.Where(x => uniqueKeys.Add(x.DataField))
    .ToDictionary(x => x.DataField.ToLowerInvariant());

    foreach ((string fieldName, string totalFieldName) in fieldNames) {
    PXGridColumn footerColumn = footerColumns[fieldName.ToLowerInvariant()];
    int timeValue
    = graph.Document.Cache.GetValue(timeCard, totalFieldName) as int
    ? ?? 0;
    TimeSpan timeSpent = TimeSpan.FromMinutes(timeValue);
    string formattedTime = string.Format(
    timeFormat, (int)timeSpent.TotalHours, Math.Abs(timeSpent.Minutes));
    footerColumn.Footer.Text = formattedTime;
    }
    }

 

As a side note, in Modern UI, this is much easier, as indicated here.