skills/flexcel-net/SKILL.md
Use when writing C# / VB.NET / F# code that reads, writes, manipulates, or exports Excel (.xlsx / .xls) files, generates PDF or HTML from Excel, or produces data-driven reports with FlexCel Studio for .NET (TMS Software). Triggers include Excel/xlsx from C#, XlsFile, FlexCelReport, FlexCelPdfExport, FlexCelHtmlExport, FlexCelImgExport, ExcelFile, PdfWriter, .NET Excel export, ASP.NET Excel generation, .NET MAUI Excel, Native AOT + Excel, and Excel reporting from .NET.
npx skillsauth add tmssoftware/skills flexcel-netInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill helps write C# / VB.NET / F# code that uses FlexCel — the TMS Software library for working with Excel .xlsx / .xls files, exporting to PDF / HTML / SVG / images, and generating data-driven reports from templates. Works with .NET Framework 4.6+, .NET Core / .NET 5+, .NET Standard 2.0+, .NET MAUI, Xamarin, and .NET 9 Native AOT (with caveats — see below).
Activate whenever the user wants to, from .NET code:
.xlsx or .xls) — cell values, formulas, formatting.FlexCel does not require Excel or any Office installation on the target machine. No OLE/COM, no interop. Fully managed — works on Windows, Linux, macOS, iOS, and Android.
Before writing code, decide which API fits the task:
| If the user wants to… | Use | Why |
|-----------------------|-----|-----|
| Read existing files, or build files cell-by-cell in code | XlsFile API (FlexCel.XlsAdapter) | Full programmatic control; no designer required; Native-AOT-safe. |
| Produce the same report repeatedly from changing data, with a styled layout | FlexCelReport + Excel template (FlexCel.Report) | Non-programmers can edit the template in Excel; code only provides data. |
When the user says "generate a report with company logo / nice formatting / many rows from a database", prefer Reports. When they say "read this file and extract values" or "create an Excel file with these calculations", prefer the API.
You can combine both: run a report to produce an in-memory XlsFile, then manipulate it with the API, then export to PDF.
NuGet package: TMS.FlexCel (includes almost all functionality). Install via dotnet add package TMS.FlexCel after configuring the TMS NuGet source — FlexCel is hosted at TMS's own NuGet feed, not on nuget.org. See guides/installation-guide.md in the doc source for feed setup.
Optional companion packages:
TMS.FlexCel.WinForms — WinForms preview / grid components.TMS.FlexCel.WebForms — legacy WebForms viewer (rarely needed).Namespaces — add per task:
| Task | using |
|------|---------|
| Any FlexCel code | using FlexCel.Core; |
| Read / write xls/xlsx | using FlexCel.XlsAdapter; |
| PDF / HTML / image export, autofitting | using FlexCel.Render; |
| Low-level PDF access (sign, PDF/A, standalone PDF) | using FlexCel.Pdf; |
| Template-based reports | using FlexCel.Report; |
| WinForms components | using FlexCel.Winforms; |
| ASP.NET helpers | using FlexCel.AspNet; |
Note: Unlike the VCL edition, .NET has no platform-support unit/assembly to register in the entry point — all platform integration ships with the core package. Just reference TMS.FlexCel and you're done.
xls.SetCellValue(1, 1, ...) writes to A1. XF (format) indices are the single exception — they are 0-based.T prefix on class names. VCL has TXlsFile, TFlexCelReport, TFlexCelPdfExport. .NET has XlsFile, FlexCelReport, FlexCelPdfExport. However value-type structs keep the T — TFormula, TFlxFormat, TCellAddress, TRichString, TExcelFileFormat, TFlxFormulaErrorValue.GetCellValue returns object. There is no TCellValue discriminated union in .NET. Dispatch with is pattern matching:
if (cell == null) { /* empty */ }
else if (cell is string s) { /* plain text */ }
else if (cell is TRichString rs) { /* rich text */ }
else if (cell is double d) { /* number (dates too!) */ }
else if (cell is bool b) { /* boolean */ }
else if (cell is TFlxFormulaErrorValue) { /* #DIV/0 etc. */ }
else if (cell is TFormula f) { /* formula */ }
ColCount — it scans the whole sheet. Use ColCountInRow(row) + GetCellValueIndexed(row, colIdx, ref XF) + ColFromIndex(row, colIdx) — this is sparse-aware and dramatically faster on real files.double. Excel stores dates as numbers with a date format. Cell returns double. Check the cell's XF number-format to know it's a date (or use TFlxNumberFormat.FormatValue helpers).XlsFile, FlexCelReport, and the export classes hold the full workbook in memory. They are fully managed — GC handles cleanup. However, the export classes (FlexCelPdfExport, FlexCelHtmlExport, FlexCelImgExport) and FlexCelReport implement IDisposable; wrap them in using. XlsFile does not require using, but don't hold big workbooks as long-lived statics.XlsFile and the exporters are fully supported. FlexCelReport uses reflection on your POCO types — annotate them with [DynamicallyAccessedMembers(...)] or reports fail silently after trimming. See references/pitfalls.md.All examples are C#. For VB.NET, translate syntactically — APIs are identical.
using System;
using System.IO;
using FlexCel.Core;
using FlexCel.XlsAdapter;
class Program
{
static void Main()
{
// Empty workbook: 1 sheet, Excel-2019 default formatting.
var xls = new XlsFile(1, TExcelFileFormat.v2019, true);
xls.SetCellValue(1, 1, "Hello from FlexCel!"); // A1 text
xls.SetCellValue(2, 1, 7); // A2 number (stored as double)
xls.SetCellValue(3, 1, 11.3); // A3 number
xls.SetCellValue(4, 1, new TFormula("=Sum(A2:A3)")); // A4 formula
xls.Save(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
"test.xlsx"));
}
}
Key points:
(1, 1) = A1..xlsx → OOXML, .xls → BIFF8). Override via xls.Save(stream, TFileFormats.Xlsx) when saving to streams.SetCellValue(1, 1, "7") writes a string "7"; SetCellValue(1, 1, 7) writes a number 7. Type dispatch happens through method overloads.using System;
using System.IO;
using FlexCel.Core;
using FlexCel.XlsAdapter;
void ReadExcel(string path)
{
var xls = new XlsFile(path);
xls.ActiveSheetByName = "Sheet1"; // or: xls.ActiveSheet = 1..xls.SheetCount
for (int row = 1; row <= xls.RowCount; row++)
{
// Use ColCountInRow, NOT ColCount — much faster. See performance guide.
for (int colIndex = 1; colIndex <= xls.ColCountInRow(row); colIndex++)
{
int XF = -1;
object cell = xls.GetCellValueIndexed(row, colIndex, ref XF);
var addr = new TCellAddress(row, xls.ColFromIndex(row, colIndex));
string kind =
cell == null ? "empty"
: cell is TRichString ? "rich string"
: cell is string ? "string"
: cell is double ? "number"
: cell is bool ? "bool"
: cell is TFlxFormulaErrorValue ? "error"
: cell is TFormula ? "formula"
: "unknown";
Console.WriteLine($"Cell {addr.CellRef} {kind}: {cell}");
}
}
}
Key points:
ColCountInRow + GetCellValueIndexed + ColFromIndex. The three together skip empty cells and give you the real column number of each non-empty cell.GetCellValueIndexed takes XF by ref and writes the cell's format index into it.cell == null means the cell is empty (never allocated). A cell containing an empty string is a different thing.using FlexCel.Core;
using FlexCel.XlsAdapter;
using FlexCel.Render;
void XlsxToPdf(string src, string dst)
{
var xls = new XlsFile(src);
using var pdf = new FlexCelPdfExport(xls, true); // true = allow overwrite
pdf.Export(dst); // all visible sheets, honoring Excel page setup
}
For PDF/A, font subsetting, digital signatures, multi-workbook PDFs, or tuning fonts on Linux/Docker see references/pdf-html-export.md.
Assume an Excel template invoice-template.xlsx already exists, with tags like <#Customers.Name> inside a named range __Customers__ spanning the repeating row(s).
using System;
using System.Data;
using FlexCel.Core;
using FlexCel.XlsAdapter;
using FlexCel.Report;
void RunReport(DataTable customers)
{
using var report = new FlexCelReport(true); // true = allow overwrite
// Supply data sources
report.AddTable("Customers", customers); // DataTable / DataSet / IEnumerable<T>
// Scalar values
report.SetValue("ReportDate", DateTime.Now);
report.SetValue("CompanyName", "Acme Corp");
report.Run("invoice-template.xlsx", "invoice-output.xlsx");
}
AddTable overloads (the most common):
report.AddTable("Customers", customerList); // IEnumerable<T> / List<T> / IQueryable<T>
report.AddTable("Customers", customerDataTable); // DataTable
report.AddTable(customerDataSet); // DataSet — each contained DataTable by name
report.AddTable(myCustomerList); // single-arg: band name inferred from type name
To output directly to PDF — run the report into a fresh XlsFile, then pipe that through FlexCelPdfExport:
var outXls = new XlsFile();
report.Run("template.xlsx", outXls);
using var pdf = new FlexCelPdfExport(outXls, true);
pdf.Export("report.pdf");
For the full tag language and template-design conventions see references/reports-cheatsheet.md.
Load a reference file only when the task actually needs it — keeps context lean for simple tasks.
references/api-cheatsheet.md — deeper XlsFile / ExcelFile usage: formatting, fonts, colors, merging, row/column sizing, comments, images, charts, data validation, protection, named ranges, InsertAndCopyRange / DeleteRange / MoveRange, sheet management, streams, recalc, virtual mode.references/reports-cheatsheet.md — full tag reference, named-range conventions for bands, master-detail, config sheets, user functions, events.references/pdf-html-export.md — FlexCelPdfExport, FlexCelHtmlExport, FlexCelImgExport options: PDF/A, font embedding, digital signing, HTML5, image embedding, multi-workbook PDFs.references/pitfalls.md — extended gotchas, Native AOT specifics, Docker/Linux fonts, locale, barcodes, conditional formats, strict xlsx.The cheatsheets cover the common path. For anything deeper, fetch from the public documentation source:
https://raw.githubusercontent.com/tmssoftware/TMS-FlexCel.NET-doc-src/main/<path>.md
guides/api-developer-guide.md, guides/reports-developer-guide.md, guides/reports-tag-reference.md, guides/pdf-exporting-guide.md, guides/html-exporting-guide.md, guides/performance-guide.md, guides/multiplatform-guide.mdtips/<topic>.md (one file per tip — includes native-aot.md)api/FlexCel.XlsAdapter/XlsFile/<MemberName>.md, api/FlexCel.Report/FlexCelReport/<MemberName>.md, etc.https://doc.tmssoftware.com/flexcel/net/index.htmlhttps://github.com/tmssoftware/TMS-FlexCel.NET-demosUse WebFetch on the raw markdown URL when you need to confirm a signature or pull an official example. Prefer the raw markdown over the rendered HTML.
using declarations / blocks for FlexCelReport, FlexCelPdfExport, FlexCelHtmlExport, FlexCelImgExport. They're IDisposable.XlsFile does not implement IDisposable; don't wrap it in using. Let it go out of scope and GC will collect it.SetCellValue(1, 1, ...)) — never pretend indices are 0-based.is pattern matching (or switch expressions on type) for GetCellValue results — don't cast blindly.FlexCelPdfExport.GetFontFolder or GetFontData events.FlexCelReport.AddTable with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicMethods)]. Without it, trimming will silently strip property accessors.api/<namespace>/<class>/<member>.md in the doc source, or tell the user to verify with APIMate.development
Use when writing Delphi / FreePascal / C++Builder code that reads, writes, manipulates, or exports Excel (.xlsx / .xls) files, generates PDF or HTML from Excel, or produces data-driven reports with FlexCel Studio for VCL and FireMonkey (TMS FlexCel). Triggers include Excel/xlsx from Delphi, TXlsFile, TFlexCelReport, TFlexCelPdfExport, TFlexCelHtmlExport, FireMonkey Excel export, Lazarus Excel, and Excel reporting from Pascal.
testing
Save, load, update, delete, merge, and navigate entity objects using TMS Aurelius ORM (TObjectManager). Use when the user asks how to persist or retrieve data with Aurelius, manage object lifetime, work with associations or collections at runtime, handle transactions, use cached updates, or control concurrency. Does NOT cover query DSL or criteria/projections (those are in a separate skill). Triggers on requests like "save an entity with Aurelius", "load a customer from the database", "add items to a collection", "how do I update an object", "flush changes", "delete a record with Aurelius", "merge a transient object", "how do transactions work in Aurelius", "batch updates Aurelius".
testing
Map Delphi classes to a relational database using TMS Aurelius ORM attributes. Use when the user asks to create entity classes, add Aurelius mapping to existing classes, fix or review mapping attributes, explain how a class is mapped, or work with associations, inheritance, automapping, nullable fields, blobs, or composite identifiers. Triggers on requests like "create Aurelius entities for...", "map this class to Aurelius", "add ORM mapping", "fix the mapping on this class", "how do I map a one-to-many in Aurelius".
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.