Releases: sveinungf/spreadcheetah
v1.19.0
Features
- Source generator: Support for ignoring properties with the
ColumnIgnore
attribute (#76). An example can be seen in the wiki. - Source generator: Support for specifying cell format on a property with the
CellFormat
attribute (#43). More details with an example in the wiki. - The package now includes a Roslyn analyzer. Previously the source generator itself would emit warnings and errors about incorrect usage (such as combinations of attributes that are not supported), but this is now handled by the Roslyn analyzer instead. This gives the following improvements:
- Diagnostics (e.g. warnings and errors) will now show up with squiggly lines in e.g. Visual Studio. They will also appear without requiring a solution build.
- The severity of the diagnostics can now be configured in an
.editorconfig
file. This should be the preferred way going forward, and for that reason theSuppressWarnings
option on theWorksheetRowGenerationOptions
attribute is now marked as obsolete.
Bug fixes
- Fix for invalid code being generated by the source generator if the
WorksheetRow
attribute type had an indexer.
v1.18.0
v1.17.0
Features
- Support for named styles. A named style is created by passing the name as the second argument to
Spreadsheet.AddStyle
. An optional visibility parameter can also be set that determines if the style name should be visible in Excel. - Source generator: Support for using styling (#44). The
CellStyle
attribute can now be placed on a property to reference a named style. More details with an example in the wiki. - Source generator: Support for custom converters to control how property values are mapped to cells (#67). This is done by implementing
CellValueConverter<T>
and using it on a property with theCellValueConverter
attribute. More details with an example in the wiki. Thanks to @Ashymonth for the contribution! StyledCell
andCell
now have new constructors so they can be created fromDataCell
.
Performance improvements
- Minor improvements to generated IL for
SpreadsheetUtility
methods.
v1.16.0
Features
- Added attribute
ColumnWidth
, which can be used to set fixed column widths when using the source generator. The column widths must be set when starting a worksheet, and a new overload ofSpreadsheet.StartWorksheetAsync
has been added for convenience. Here is an example:public class Book { [ColumnWidth(50)] public string Title { get; set; } [ColumnWidth(20)] public string Author { get; set; } } [WorksheetRow(typeof(Book))] public partial class BookContext : WorksheetRowContext;
In case you need to use// Alternative 1: Use the new overload of StartWorksheetAsync. // It takes the context type generated by the source generator as the second parameter. await spreadsheet.StartWorksheetAsync("Sheet", BookContext.Default.Book); var book = new Book { Title = "A Game of Thrones", Author = "George R. R. Martin" }; await spreadsheet.AddAsRowAsync(book, BookContext.Default.Book);
WorksheetOptions
, you can instead create an instance with the column widths like this:// Alternative 2: Create an instance of WorksheetOptions from the context type. // The WorksheetOptions instance will be created with the column widths from the class attributes. var options = BookContext.Default.Book.CreateWorksheetOptions(); // Can now set additional options, for example frozen columns. options.FrozenColumns = 1; await spreadsheet.StartWorksheetAsync("Sheet", options); var book = new Book { Title = "A Game of Thrones", Author = "George R. R. Martin" }; await spreadsheet.AddAsRowAsync(book, BookContext.Default.Book);
- Added attribute
CellValueTruncate
, which can be used to truncate string values when using the source generator. Here is an example:public class LoremIpsum { [CellValueTruncate(15)] public string Text { get; set; } } [WorksheetRow(typeof(LoremIpsum))] public partial class LoremIpsumContext : WorksheetRowContext;
In this example, the value in cell A1 will bevar loremIpsum = new LoremIpsum { Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }; await spreadsheet.AddAsRowAsync(loremIpsum, LoremIpsumContext.Default.LoremIpsum);
Lorem ipsum dol
(the 15 first characters). A string consisting of fewer characters than the truncate length will have its whole value written to the cell. Internally the implementation will useReadOnlyMemory<char>
to avoid additional string allocations when truncating strings.
Bug fixes
- Fixed a compilation issue for UWP when using .NET Native (issue #58).
WorksheetOptions.Column(int columnNumber)
will no longer allow a column number larger than 16384 (maximum in Excel). An exception will be thrown if attempting to use a larger number.
Performance improvements
- Smaller loop performance improvements in the hot path when adding rows to a worksheet.
- Smaller improvements to memory allocations.
v1.15.0
Features
-
Support for inheritance when using the source generator. By default, the source generator will only create columns from properties defined directly on the type passed to the
WorksheetRow
attribute. With the newInheritColumns
attribute, the base class will be taken into account as well. Here is an example:public class Vehicle { public int Wheels { get; set; } public bool HasEngine { get; set; } } [InheritColumns] public class Car : Vehicle { public string Make { get; set; } public string Model { get; set; } } [WorksheetRow(typeof(Car))] public partial class CarContext : WorksheetRowContext;
In this example, the columns will be created in this order:
Wheels
,HasEngine
,Make
,Model
. The order can be customized by settingDefaultColumnOrder
on theInheritColumns
attribute, or by using theColumnOrder
attribute directly on the properties. Thanks to @Ashymonth for the contribution! -
String cells can now be created from
ReadOnlyMemory<char>
in addition tostring
. New constructors have been added toCell
,StyledCell
, andDataCell
.
Performance improvements
- Most of the
DataCell
constructors are now branchless on .NET 8 and later. - Improved performance of creating
workbook.xml
(metadata file that is part of an XLSX file).
v1.14.0
Features
- Support for creating hidden columns by using
ColumnOptions.Hidden
. Thanks to @BredStik for the contribution! - The
ColumnHeader
attribute can now reference resource files (ResX) to have localized header names. For example, to reference a resource keyHeader_FirstName
from resource fileMyResources.resx
:Note that the resource file must have a public access modifier. A row of header names can then in turn be created in a worksheet by calling[ColumnHeader(typeof(MyResources), nameof(MyResources.Header_FirstName))] public string FirstName { get; }
Spreadsheet.AddHeaderRowAsync
. This feature is not just limited to resource files, and can also similarly reference other public static properties.
v1.13.1
v1.13.0
Features
-
Support for creating a row of header names using the source generator. The new
Spreadsheet.AddHeaderRowAsync
method takes the type created by the source generator as the first argument, and an optional style as the second argument. By default the header name for a property will be the property name. E.g. this property:public string Surname { get; }
will create the header name
"Surname"
. The header name can be customized by using theColumnHeader
attribute. If we want to have header name"Last name"
instead, we can decorate the property with the attribute like this:[ColumnHeader("Last name")] public string Surname { get; }
-
Support for customizing the order between columns when using the source generator. By default, the order is decided by the order of the properties in the class/struct. The order can now be customized by using the
ColumnOrder
attribute. E.g. for these properties:[ColumnOrder(3)] public string LastName { get; } [ColumnOrder(1)] public string FirstName { get; } [ColumnOrder(2)] public string? MiddleName { get; }
the column order would be:
FirstName
,MiddleName
,LastName
. -
Illegal control characters from strings will now be ignored when writing the resulting XLSX file. These are the characters from
\x00
to\x1f
(except CR, LF, and TAB). These control characters can otherwise make the XLSX file invalid.
Performance improvements
-
All
Spreadsheet.AddRowAsync
methods now have improved performance by choosing between different implementations of the cell writers internally based onSpreadCheetahOptions.WriteCellReferenceAttributes
. -
SpreadsheetUtility.GetColumnName
will no longer allocate when the result is a one-character column name. Cases with longer column names also have improved performance, especially when running on .NET 8 or later. -
The source generator should now have better performance as well, and the source generator pipeline is now cachable. This should lead to a smaller impact on compile time for projects that are using the source generator. Thanks to Andrew Lock for his excellent article series about source generators!
v1.12.0
Features
- Support for adding images that are embedded into the spreadsheet. An example of how to do this can be seen in the wiki. Currently only PNG images are supported.
- The source generator now supports creating cells from
DateTime
properties. Thanks to @Misiu for the contribution! - The source generator now also supports creating cells from
Nullable<T>
properties (e.g.int?
). Thanks to @Misiu for the contribution! - Greatly reduced memory allocations for data validations, cell merges, and notes by using pooled arrays internally.
- Other smaller performance improvements, where most of these take effect when targeting .NET 7 or later.
- The library is now being marked as Native AOT compatible when targeting .NET 8 or later.
Other changes
- The .NET Standard 2.1 target of the library has been removed, due to .NET Core 3.1 and .NET 5 being out of support for a while. .NET Standard 2.0 will still be supported going forward.
v1.11.0
Features
- Support for adding a note to a cell with
Spreadsheet.AddNote(string cellReference, string noteText)
. Currently plain-text notes without styling are supported. - Added utility method
SpreadsheetUtility.TryParseColumnName
. It will try to parse a column name (e.g.A
) to its column number (e.g. 1). - The
Style
class now has aFormat
property that is intended to replace theNumberFormat
property. Previously there was an issue that a format could automatically use one of the locale dependent standard formats from Excel, even if the user wanted to specify a custom format. TheFormat
property allows for explicitly specifying whether the number format should be a custom or a standard one. Thanks to @AlexVallat for the contribution!
Breaking changes
- The
NumberFormat
property onStyle
has been marked as obsolete. Existing code should migrate to use theFormat
property instead, either by usingFormat = NumberFormat.Standard(...)
to use one of the standard formats from Excel, orFormat = NumberFormat.Custom(...)
to use a custom format.
Other changes
- The assembly is now signed with a strong name.
- The .NET Standard targets of the library are no longer marked as being trimmable. This is because those targets don't support trimming (https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/8.0/trimming-unsupported-targetframework). .NET 6 and later targets are still marked as being trimmable.