PanoramicData.SheetMagic
3.1.140
dotnet add package PanoramicData.SheetMagic --version 3.1.140
NuGet\Install-Package PanoramicData.SheetMagic -Version 3.1.140
<PackageReference Include="PanoramicData.SheetMagic" Version="3.1.140" />
<PackageVersion Include="PanoramicData.SheetMagic" Version="3.1.140" />
<PackageReference Include="PanoramicData.SheetMagic" />
paket add PanoramicData.SheetMagic --version 3.1.140
#r "nuget: PanoramicData.SheetMagic, 3.1.140"
#:package PanoramicData.SheetMagic@3.1.140
#addin nuget:?package=PanoramicData.SheetMagic&version=3.1.140
#tool nuget:?package=PanoramicData.SheetMagic&version=3.1.140
PanoramicData.SheetMagic
Easily save/load data to/from Excel (XLSX) documents using strongly-typed C# classes.
Requirements
- .NET 10.0 - This library targets .NET 10.0 only
- DocumentFormat.OpenXml 3.x - required from 3.1 onwards
Versioning
The major.minor prefix comes from version.json and the patch number is the
Nerdbank.GitVersioning commit height. The prefix sat at 3.0 from 2020 to 2026 across 53
releases and is not used to signal API breaks - check the package dependencies and release
notes rather than inferring compatibility from the version alone.
The height restarts from zero whenever the prefix changes, which would have dropped the
patch number from 136 to 1 when the prefix moved to 3.1. versionHeightOffset in
version.json compensates for that, so numbering continues from where the 3.0 series
left off rather than restarting. Do not remove it: without it the next build would be
numbered below releases that are already published.
One such change is worth calling out, because the package metadata states it but the version number does not: only one DocumentFormat.OpenXml assembly can load per process, and from 3.1 SheetMagic requires OpenXml 3.x. An application that must stay on OpenXml 2.x should remain on 3.0.136 or earlier.
Installation
dotnet add package PanoramicData.SheetMagic
Features
- ? Strongly-typed - Work with your own C# classes
- ? Simple API - Easy to read and write XLSX files
- ? Multiple sheets - Add and read multiple worksheets
- ? Styling support - Apply table styles to your data
- ? Extended properties - Support for dynamic properties via
Extended<T> - ? Streams and files - Work with both
FileInfoandStreamobjects - ? Type safe - Full support for common .NET types including nullable types
Quick Start
Writing to a file
using PanoramicData.SheetMagic;
// Define your class
public class Thing
{
public string PropertyA { get; set; }
public int PropertyB { get; set; }
}
// Create some data
var things = new List<Thing>
{
new Thing { PropertyA = "Value 1", PropertyB = 1 },
new Thing { PropertyA = "Value 2", PropertyB = 2 },
};
// Write to Excel file
var fileInfo = new FileInfo($"Output {DateTime.UtcNow:yyyyMMddTHHmmss}Z.xlsx");
using var workbook = new MagicSpreadsheet(fileInfo);
workbook.AddSheet(things);
workbook.Save();
Reading from a file
using PanoramicData.SheetMagic;
// Read from Excel file
using var workbook = new MagicSpreadsheet(fileInfo);
workbook.Load();
// Read from default worksheet (first sheet)
var cars = workbook.GetList<Car>();
// Read from a specific worksheet by name
var animals = workbook.GetList<Animal>("Animals");
Advanced Features
Working with Streams
// Write to a stream
using var stream = new MemoryStream();
using (var workbook = new MagicSpreadsheet(stream))
{
workbook.AddSheet(data);
workbook.Save();
}
// Read from a stream
stream.Position = 0;
using var workbook = new MagicSpreadsheet(stream);
workbook.Load();
var items = workbook.GetList<MyClass>();
Multiple Sheets
using var workbook = new MagicSpreadsheet(fileInfo);
workbook.AddSheet(cars, "Cars");
workbook.AddSheet(animals, "Animals");
workbook.AddSheet(products, "Products");
workbook.Save();
Applying Table Styles
var options = new AddSheetOptions
{
TableOptions = new TableOptions
{
Name = "MyTable",
DisplayName = "MyTable1",
XlsxTableStyle = XlsxTableStyle.TableStyleMedium2,
ShowRowStripes = true,
ShowColumnStripes = false,
ShowFirstColumn = false,
ShowLastColumn = false
}
};
workbook.AddSheet(data, "StyledSheet", options);
Conditional Formatting
Conditional formatting is configured through AddSheetOptions.ConditionalFormats.
The object model is intentionally close to Excel's own configuration model:
ConditionalFormatselects one or more output columns, or all columns whenColumnNamesis omitted.ConditionalFormatRuledescribes one Excel rule such asCellIs,ContainsBlanks, orContainsErrors.ConditionalFormatStyledefines the differential format Excel applies when the rule matches.
ColumnNames must match the final header text written to Excel.
If PropertyHeaders is set, use those values.
Otherwise use the Description attribute value or the property name.
using System.Drawing;
using PanoramicData.SheetMagic;
var rows = new[]
{
new ReportRow { Name = null, Description = "Missing name", Score = null },
new ReportRow { Name = "Bravo", Description = "High score", Score = 9 },
new ReportRow { Name = "Charlie", Description = null, Score = 4 }
}.ToList();
var options = new AddSheetOptions
{
ConditionalFormats =
[
new ConditionalFormat
{
ColumnNames = ["Name", "Description"],
Rules =
[
new ConditionalFormatRule
{
RuleType = ConditionalFormatRuleType.ContainsBlanks,
Style = new ConditionalFormatStyle
{
BackgroundColor = Color.Red
}
}
]
},
new ConditionalFormat
{
ColumnNames = ["Score"],
Rules =
[
new ConditionalFormatRule
{
RuleType = ConditionalFormatRuleType.ContainsBlanks,
Style = new ConditionalFormatStyle
{
BackgroundColor = Color.Red
}
},
new ConditionalFormatRule
{
RuleType = ConditionalFormatRuleType.CellIs,
Operator = ConditionalFormatOperator.GreaterThan,
Formula = "5",
Style = new ConditionalFormatStyle
{
FontColor = Color.Green,
FontWeight = FontWeight.Bold
}
}
]
},
new ConditionalFormat
{
Rules =
[
new ConditionalFormatRule
{
RuleType = ConditionalFormatRuleType.ContainsErrors,
Style = new ConditionalFormatStyle
{
FontWeight = FontWeight.Bold
}
}
]
}
]
};
using var workbook = new MagicSpreadsheet(new FileInfo("ConditionalFormatting.xlsx"));
workbook.AddSheet(rows, "Report", options);
workbook.Save();
public sealed class ReportRow
{
public string? Name { get; set; }
public string? Description { get; set; }
public int? Score { get; set; }
}
Supported rule types currently include:
CellIsExpressionContainsBlanksNotContainsBlanksContainsErrorsNotContainsErrorsContainsTextNotContainsTextBeginsWithEndsWithDuplicateValuesUniqueValuesTop10AboveAverage
Custom Property Headers
Use the Description attribute to customize column headers:
using System.ComponentModel;
public class Employee
{
public int Id { get; set; }
[Description("Full Name")]
public string Name { get; set; }
[Description("Hire Date")]
public DateTime HireDate { get; set; }
}
Property Filtering
// Include only specific properties
var options = new AddSheetOptions
{
IncludeProperties = new[] { "Name", "Age", "City" }
};
workbook.AddSheet(people, "Filtered", options);
// Exclude specific properties
var options = new AddSheetOptions
{
ExcludeProperties = new[] { "InternalId", "Password" }
};
workbook.AddSheet(users, "Public", options);
Extended Properties (Dynamic Properties)
Work with objects that have both strongly-typed and dynamic properties:
var extendedData = new List<Extended<MyClass>>
{
new Extended<MyClass>(
new MyClass { Id = 1, Name = "Item 1" },
new Dictionary<string, object?>
{
{ "DynamicProp1", "Value1" },
{ "DynamicProp2", 42 }
}
)
};
workbook.AddSheet(extendedData);
workbook.Save();
// Reading extended properties
var loadedData = workbook.GetExtendedList<MyClass>();
foreach (var item in loadedData)
{
Console.WriteLine($"{item.Item.Name}");
foreach (var prop in item.Properties)
{
Console.WriteLine($" {prop.Key}: {prop.Value}");
}
}
Supported Types
- Primitives:
int,long,short,uint,ulong,ushort - Floating point:
float,double,decimal - Boolean:
bool - Dates:
DateTime,DateTimeOffset - Strings:
string - Enums (stored as text)
- Lists:
List<string>(with configurable delimiter) - All nullable versions of the above
Options
Configure behavior with the Options class:
var options = new Options
{
StopProcessingOnFirstEmptyRow = true,
IgnoreUnmappedProperties = true,
EmptyRowInterpretedAsNull = false,
LoadNullExtendedProperties = true,
ListSeparator = ";"
};
using var workbook = new MagicSpreadsheet(fileInfo, options);
Known Limitations
- JObject Support: Direct
JObjectserialization is not yet supported. UseExtended<object>instead. - Nested Complex Objects: Properties of type
List<ComplexType>cannot be loaded from Excel (though they can be saved as delimited strings). - Large Integer Precision: Excel stores all numbers as doubles, so very large
Int64/UInt64values (nearMaxValue) may lose precision. - Special Values:
double.NaNandnullnullable types are stored as empty strings in Excel.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- DocumentFormat.OpenXml (>= 3.5.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PanoramicData.SheetMagic:
| Package | Downloads |
|---|---|
|
PanoramicData.SheetMagic.Benchmarks
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.1.140 | 0 | 8/30/2026 |
| 3.1.138 | 0 | 8/29/2026 |
| 3.1.1 | 0 | 8/29/2026 |
| 3.0.136 | 282 | 8/9/2026 |
| 3.0.130 | 450 | 6/7/2026 |
| 3.0.129 | 210 | 5/12/2026 |
| 3.0.127 | 126 | 5/12/2026 |
| 3.0.126 | 133 | 5/12/2026 |
| 3.0.124 | 220 | 4/13/2026 |
| 3.0.122 | 239 | 4/5/2026 |
| 3.0.118 | 544 | 12/21/2025 |
| 3.0.117 | 241 | 12/21/2025 |
| 3.0.114 | 406 | 11/23/2025 |
| 3.0.109 | 407 | 10/27/2025 |
| 3.0.106 | 528 | 9/2/2025 |
| 3.0.105 | 676 | 5/21/2025 |
| 3.0.104 | 300 | 5/8/2025 |
| 3.0.101 | 2,873 | 10/16/2023 |
| 3.0.98 | 289 | 10/9/2023 |
| 3.0.96 | 940 | 7/13/2023 |
Enhanced logic to handle missing text cells (this can happen with empty strings, if they have no formatting, and is a normal Excel optimization) in the Excel file's XML. These cell values are now returned as empty strings for consistency.