Defining a table with DocumentFormat.OpenXml.Spreadsheet
losol
0
Reputation points
I have successfully managed to make an excel file which is exporting my registration model
public async Task ExportParticipantListToExcelAsync(
Stream stream,
RegistrationListRequest request)
{
try
{
using var spreadsheetDocument = SpreadsheetDocument.Create(
stream,
SpreadsheetDocumentType.Workbook
);
var workbookPart = spreadsheetDocument.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
var sheetData = new SheetData();
var columnConfig = ColumnConfig.GetDefaultConfig();
WriteHeaderRow(sheetData, columnConfig);
// Write data rows
var reader = RegistrationPageReaderFactory.CreateRegistrationPageReader(
_registrationRetrievalService,
request
);
int dataRowCount = 0;
while (await reader.HasMoreAsync())
{
var registrations = await reader.ReadNextAsync();
foreach (var registration in registrations)
{
WriteDataRow(sheetData, registration);
dataRowCount++;
}
}
// Set the worksheet for the worksheet part
worksheetPart.Worksheet = new Worksheet(sheetData);
// Use the helper to add a unique sheet
ExcelSheetHelper.AddUniqueSheet(workbookPart, worksheetPart, "Participants");
// Define the Excel table
ExcelTableBuilder.DefineExcelTable(worksheetPart, columnConfig, dataRowCount);
// Save the workbook
workbookPart.Workbook.Save();
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while exporting the participant list to Excel.");
throw;
}
}
private static void AppendRowToSheet(SheetData sheetData, List<string> cellValues)
{
var row = new Row();
foreach (var value in cellValues)
{
row.Append(new Cell
{
CellValue = new CellValue(string.IsNullOrWhiteSpace(value) ? "a" : value),
DataType = CellValues.String
});
}
sheetData.Append(row);
}
private static void WriteHeaderRow(SheetData sheetData, List<ColumnConfig> columns)
{
var headerValues = columns.Select(column => column.Header).ToList();
AppendRowToSheet(sheetData, headerValues);
}
private static void WriteDataRow(SheetData sheetData, Registration registration)
{
var config = ColumnConfig.GetDefaultConfig();
if (config == null || config.Count == 0)
{
throw new InvalidOperationException("Column configuration cannot be null or empty.");
}
var dataValues = config.Select(column => column.DataExtractor(registration)).ToList();
AppendRowToSheet(sheetData, dataValues);
}
}
This is columnconfig
public enum ExcelColumnType
{
String,
Number,
Date,
Boolean,
}
public class ColumnConfig
{
public string Header { get; set; }
public Func<Registration, string> DataExtractor { get; set; }
public ExcelColumnType ColumnType { get; set; } = ExcelColumnType.String;
public static List<ColumnConfig> GetDefaultConfig()
{
return new List<ColumnConfig>
{
new ColumnConfig
{
Header = "RegistrationId",
DataExtractor = reg => reg.RegistrationId.ToString(),
ColumnType = ExcelColumnType.Number
},
new ColumnConfig
{
Header = "UserFirstName",
DataExtractor = reg => reg.User?.GivenName ?? ""
},
// omitted some fields for brevity
};
}
}
I was hoping that this would define a table for me:
public static void DefineExcelTable(
WorksheetPart worksheetPart,
List<ColumnConfig> columnConfig,
int dataRowCount
)
{
uint nextTableId = (uint)worksheetPart.GetPartsOfType<TableDefinitionPart>().Count() + 1;
var table = new Table
{
Id = nextTableId,
Name = "ParticipantList",
Reference = $"A1:{ExcelColumnName.GetLetters(columnConfig.Count)}{dataRowCount + 1}",
};
var tableStyleInfo = new TableStyleInfo
{
Name = "TableStyleMedium9",
ShowFirstColumn = true,
ShowLastColumn = true,
ShowRowStripes = true,
ShowColumnStripes = true,
};
table.AppendChild(tableStyleInfo);
var tableColumns = new TableColumns { Count = (uint)columnConfig.Count };
uint columnIndex = 1;
foreach (var config in columnConfig)
{
var tableColumn = new TableColumn
{
Id = columnIndex,
Name = config.Header ?? $"Column{columnIndex}"
};
tableColumns.Append(tableColumn);
columnIndex++;
}
table.Append(tableColumns);
var tableDefinitionPart = worksheetPart.GetPartsOfType<TableDefinitionPart>().FirstOrDefault()
?? worksheetPart.AddNewPart<TableDefinitionPart>();
tableDefinitionPart.Table = table;
tableDefinitionPart.Table.Save();
}
}
I was hoping to see this type of table:
But are currently seeing only a normal spreadsheet without table
Any tips on how to achieve this?