// Hook: AfterCalculation // Sort the "Details" sheet rows by column C, descending. // // The largest values float to the top of the distributed report regardless // of how the source data was ordered. The header row is preserved. var sheet = Workbook.Worksheets["Details"]; if (sheet == null) { AddWarning("Sheet 'Details' not found - skipping sort."); return; } var lastRow = sheet.Cells.MaxDataRow; var lastCol = sheet.Cells.MaxDataColumn; // MaxDataRow/MaxDataColumn are -1 on an empty sheet, and MaxDataRow is 0 when // there is nothing but a header row. Either way there is no data range to sort, // and CreateCellArea would be handed an end before its start. if (lastRow < 1 || lastCol < 0) { AddWarning("Sheet 'Details' has no data rows below the header - skipping sort."); return; } // Skip the header row (start at row index 1). DataSorter.Sort takes a CellArea // of start/end indices, not a Range. var sortArea = CellArea.CreateCellArea(1, 0, lastRow, lastCol); var sorter = Workbook.DataSorter; sorter.Key1 = 2; // column C (zero-based index) sorter.Order1 = SortOrder.Descending; sorter.Sort(sheet.Cells, sortArea); Logger.LogInformation($"Details sheet sorted by column C descending. Rows: {lastRow}");