FlexCel Studio for .NET
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).
When to use this skill
Activate whenever the user wants to, from .NET code:
- Read an Excel file (
.xlsxor.xls) — cell values, formulas, formatting. - Create or modify an Excel file programmatically.
- Generate reports by merging data into Excel templates.
- Export an Excel file to PDF, HTML, SVG, or images.
- Autofit rows/columns, render sheets, or measure cells.
- Target .NET Framework, .NET Core / .NET 5+, .NET MAUI, Xamarin, Blazor server, ASP.NET Core, or Native AOT.
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.
Two ways to create Excel files — pick one
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.
Package and namespace reference
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.
Critical gotchas (read this every time)
- 1-based indexing for rows, columns, and sheets.
xls.SetCellValue(1, 1, ...)writes toA1. XF (format) indices are the single exception — they are 0-based. - No
Tprefix on class names. VCL hasTXlsFile,TFlexCelReport,TFlexCelPdfExport. .NET hasXlsFile,FlexCelReport,FlexCelPdfExport. However value-type structs keep theT—TFormula,TFlxFormat,TCellAddress,TRichString,TExcelFileFormat,TFlxFormulaErrorValue. GetCellValuereturnsobject. There is noTCellValuediscriminated union in .NET. Dispatch withispattern 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 */ }- Never iterate with
ColCount— it scans the whole sheet. UseColCountInRow(row)+GetCellValueIndexed(row, colIdx, ref XF)+ColFromIndex(row, colIdx)— this is sparse-aware and dramatically faster on real files. - Dates are
double. Excel stores dates as numbers with a date format. Cell returnsdouble. Check the cell's XF number-format to know it's a date (or useTFlxNumberFormat.FormatValuehelpers). - Memory.
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) andFlexCelReportimplementIDisposable; wrap them inusing.XlsFiledoes not requireusing, but don't hold big workbooks as long-lived statics. - Use APIMate. For anything Excel-specific ("how do I add a data validation / a conditional format / a chart / a pivot table?"), the canonical answer is: build it in Excel → open the file in APIMate (ships with FlexCel, also available for Linux and macOS) → copy the generated C# or VB.NET code. Tell the user this.
- Native AOT (.NET 9+):
XlsFileand the exporters are fully supported.FlexCelReportuses reflection on your POCO types — annotate them with[DynamicallyAccessedMembers(...)]or reports fail silently after trimming. Seereferences/pitfalls.md.
Quick-start recipes
All examples are C#. For VB.NET, translate syntactically — APIs are identical.
Recipe 1 — Create an Excel file
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:
- Indices are 1-based:
(1, 1)=A1. - File format is inferred from the extension (
.xlsx→ OOXML,.xls→ BIFF8). Override viaxls.Save(stream, TFileFormats.Xlsx)when saving to streams. SetCellValue(1, 1, "7")writes a string"7";SetCellValue(1, 1, 7)writes a number7. Type dispatch happens through method overloads.
Recipe 2 — Read an Excel file
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