Skip to content

Conversation

@dependabot
Copy link
Contributor

@dependabot dependabot bot commented on behalf of github Aug 7, 2025

Updated ClosedXML from 0.95.4 to 0.105.0.

Release notes

Sourced from ClosedXML's releases.

0.105.0

What's Changed

Major enhancements

Automatic fixer of function names

Correct name for newer functions (post 2013) is not what is seen in the GUI (e.g. correct name for CONCAT is _xlfn.CONCAT). That is rather obscure fact not known to most developers. The formula setters (e.g. IXLCell.FormulaA1) now automatically fix function names, so it is stored correctly in the file.

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
// Originally required "_xlfn.CONCAT(\"hello\", \" world!\")";
ws.Cell("A1").FormulaA1 = "CONCAT(\"hello\", \" world!\")"; 

Pre-0.105
image
0.105
image

Sorting updates references

In many cases, the sorted area has a column with references. The formula often references another row. Pre-0.105, the references in the formulas weren't updated correctly.
image

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.Cell("A1").Value = 4;
ws.Cell("B1").FormulaA1 = "A1+1";
ws.Cell("A2").Value = 2;
ws.Cell("B2").FormulaA1 = "A2+1";
ws.Cell("A3").Value = 1;
ws.Cell("B3").FormulaA1 = "A3+1";

ws.Range("A1:B3").Sort(1, XLSortOrder.Ascending);

Reimplementation/refactoring of old function infrastructure

Basically all implemented functions should be more faithful to how Excel behaves and evaluation of functions should be faster. implemented functions should be "complete" in sense that they correctly work for various arguments (e.g. various forms of ROMAN or pattern search in SUMIFS).

The functions (before refactoring) had serious problems with ranges, errors or type coercion or structured references. The original parser back then didn't even parse literal arrays ({1,2,3;4,5,6}). Parser and other things were updated, but because there was ~180 functions, original implementation was kept and functions were functions were reused through an adapter. Except the adapter never worked right and there were some other serious problems.

Changes

Bugfixes

0.105.0-rc

What's Changed

Major enhancements

Automatic fixer of function names

Correct name for newer functions (post 2013) is not what is seen in the GUI (e.g. correct name for CONCAT is _xlfn.CONCAT). That is rather obscure fact not known to most developers. The formula setters (e.g. IXLCell.FormulaA1) now automatically fix function names, so it is stored correctly in the file.

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
// Originally required "_xlfn.CONCAT(\"hello\", \" world!\")";
ws.Cell("A1").FormulaA1 = "CONCAT(\"hello\", \" world!\")"; 

Pre-0.105
image
0.105
image

Sorting updates references

In many cases, the sorted area has a column with references. The formula often references another row. Pre-0.105, the references in the formulas weren't updated correctly.
image

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.Cell("A1").Value = 4;
ws.Cell("B1").FormulaA1 = "A1+1";
ws.Cell("A2").Value = 2;
ws.Cell("B2").FormulaA1 = "A2+1";
ws.Cell("A3").Value = 1;
ws.Cell("B3").FormulaA1 = "A3+1";

ws.Range("A1:B3").Sort(1, XLSortOrder.Ascending);

Reimplementation/refactoring of old function infrastructure

Basically all implemented functions should be more faithful to how Excel behaves and evaluation of functions should be faster. implemented functions should be "complete" in sense that they correctly work for various arguments (e.g. various forms of ROMAN or pattern search in SUMIFS).

The functions (before refactoring) had serious problems with ranges, errors or type coercion or structured references. The original parser back then didn't even parse literal arrays ({1,2,3;4,5,6}). Parser and other things were updated, but because there was ~180 functions, original implementation was kept and functions were functions were reused through an adapter. Except the adapter never worked right and there were some other serious problems.

Changes

Bugfixes

0.104.2

What's Changed

Full Changelog: ClosedXML/ClosedXML@0.104.1...0.104.2

0.104.1

Release notes from 0.102.1 to the 0.104.1.

Summary of breaking changes is available at docs.closedxml.io:

OpenXML SDK

OpenXML SDK has released version 3. The 0.104.0 uses it as a dependency.

XLParser replaced with ClosedParser

The XLParser has been replaced with ClosedParser. The key benefits are

  • performance - ~2μs/formula, it's likely formulas will be parseable on the demand, necessary for construction of dependency tree
  • A1/R1C1 parsing parity - both modes can be parsed with no problems
  • AST oriented - it's likely a construction of AST in memory won't even be necessary, just use AST factory to evaluate formula directly

There is also a visualizer to display AST in a browser at https://parser.closedxml.io

image

Formula Calculation

In previous version, formulas used to be calculated recursively. Each formula checked it's supporting cells for other formulas and if there were some, they were recursively evaluated. There was some logic to decrease number of evaluations. That works for a very simple cases, but isn't very good for various non-happy paths (i.e. cells weren't calculated when they should be).

This version has replaced it with a standard

  • dependency tree for checking which formulas are dirty and need to be recalculated
  • calculation chain that manages dependencies and order of formulas during calculation

For more info, see docs, the Microsoft has a page about principles Excel Recalculation
and there is one with API at docs.closedxml.io.

image

Structured references

New parser also allows a basic evaluation of structured references. Format of structured reference must use official grammar, not Excel friendly names (e.g. Pastry[@​Name] is user-friendly name for Pastry[[#This Row],[Name]]). It's now possible to

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.Cell("A1").InsertTable(new Pastry[]
{
    new("Cake", 14),
    new("Waffle", 3),
}, "Pastry");

ws.Cell("D1").FormulaA1 = "SUM(Pastry[Price])";
ws.Cell("D3").FormulaA1 = "\"Pastry \" & Pastry[[#This Row],[Name]]";
wb.RecalculateAllFormulas();
 ... (truncated)

## 0.104-rc1

A release candidate 1 for 0.104.0. 

* [Migration from 0.102 to 0.103](https://docs.closedxml.io/en/latest/migrations/migrate-to-0.103.html)
* [Migration from 0.103 to 0.104](https://docs.closedxml.io/en/latest/migrations/migrate-to-0.104.html)

Of course, this includes all stuff from [0.103.0-beta](https://github.com/ClosedXML/ClosedXML/releases/tag/0.103.0-beta). Version 0.103 never got a non-beta release.

# OpenXML SDK

OpenXML SDK has released version 3.0.1. The 0.104-rc1 uses it as a dependency. 

# Pivot tables

The internal structure of pivot tables, along with most other features, has been completely overhauled. This update should significantly reduce crashes when loading and saving workbooks containing pivot tables.

The main issue with the previous internal structure was that it didn't align with the structure used by OOXML. This was problematic because we need to support all valid files. As a result, we have to handle a wide range of inputs and correctly convert them to our internal structure, which is rather hard. A more clear 1:1 mapping with OOXML is much simpler and more reliable.

# AutoFilter

The Autofilter feature has been revamped, which includes some API changes. Its behavior is now more closely aligned with how Excel operates. The XML documentation provides detailed explanations, and there is a [dedicated documentation page](https://docs.closedxml.io/en/latest/features/autofilter.html). Several bugs have also been fixed.

For more details, refer to the [Autofilter section of the migration guide](https://docs.closedxml.io/en/latest/migrations/migrate-to-0.104.html#autofilter).

# CommonCrawl dataset

When workbook is a valid one, ClosedXML shouldn't throw on load. That is a rather high priority (more than saving or manipulation). Unfortunately, that is hard to find such areas that cause most problems.

One of activities that was going in a background is trying to use excel files around the internet (found by CommonCrawl) to evaluate how bad it is. There aren't results yet, but it is something that is going on.



# What's Changed

## Breaking changes
* First page number can be negative -> change API type to int by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2237
* Rename IXLNamedRange to IXLDefinedName by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2258

## AutoFilter
* AutoFilter rework - 1/? - Regular filter matches string. by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2238
* AutoFilter rework - 2/? - fix types for custom filters by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2239
* AutoFilter rework - 3/? - Top and average filter refactor, remove setters of internal state by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2240
* AutoFilter rework - 4/? - Top/Average filters work after loading by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2241
* AutoFilter rework - 5/? - Unify Regular and DateTimeGrouping filters by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2242
* AutoFilter rework - 6/7 - Add tests by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2243
* AutoFilter rework - 7/7 - Add documentation by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2245

## Formulas
* Update ClosedXML.Parser to 1.0 by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2250
* Implement structured references by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2251
* Replace regex-powered code for A1-R1C1 formula conversion with AST-based one by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2253
 ... (truncated)

## 0.104.0-preview2

Second test release for checking SourceLink support on nuget (first failed due to fody/PDB checksum) https://github.com/ClosedXML/ClosedXML/issues/2070

## 0.104.0-preview1

Test release for checking SourceLink support #​2070 

## 0.103.0-beta

There won't be a non-beta release for 0.103. The production release will be 0.104, not 0.103. This milestone was about fixing technical debt, but ultimately it needs some more time to mature before it is sent to the users.

There are some nice performance updates, so in spirit of release early, release often, there will be a beta package on nuget. 

# Breaking changes

Rich text is now immutable behind the scenes (and will likely be turned into immutable in the future). It should be transparent to the user, though `IXLPhonetic` no longer has a setter for its `IXLPhonetic.Text`, `IXLPhonetic.Start` and `IXLPhonetic.End` properties.

New calculation engine just works in a different way and will behave differently.

# Significant changes
## XLParser replaced with ClosedParser
The [*XLParser*](https://github.com/spreadsheetlab/XLParser) has been replaced with [*ClosedParser*](https://github.com/ClosedXML/ClosedXML.Parser). The key benefits are
* performance - ~2μs/formula, it's likely formulas will be parseable on the demand, necessary for construction of dependency tree
* A1/R1C1 parsing parity - both modes can be parsed with no problems
* AST oriented - it's likely a construction of AST in memory won't even be necessary, just use AST factory to evaluate formula directly

There is also a visualizer to display AST in a browser at **[https://parser.closedxml.io](https://parser.closedxml.io)**

![image](https://github.com/ClosedXML/ClosedXML.Parser/assets/7634052/4beaab23-4599-44d4-be7b-705178b69f99)

## Formula Calculation 

In previous version, formulas used to be calculated recursively. Each formula checked it's supporting cells for other formulas and if there were some, they were recursively evaluated. There was some  logic to decrease number of evaluations. That works for a very simple cases, but isn't very good for various non-happy paths (i.e. cells weren't calculated when they should be).

This version has replaced it with a standard 
* dependency tree for checking which formulas are dirty and need to be recalculated
* calculation chain that manages dependencies and order of formulas during calculation

For more info, see docs, the Microsoft has a page about principles [Excel Recalculation](https://learn.microsoft.com/en-us/office/client-developer/excel/excel-recalculation)
 and there is one with API at [docs.closedxml.io](https://docs.closedxml.io/en/latest/concepts/formula-calculation.html).

![image](https://github.com/ClosedXML/ClosedXML/assets/7634052/2a621044-368a-4076-b121-cefb10150a6e)

## Workbook structure

Internal structure has been cleaned up and optimized.

The dirty tracking has been moved out of cells to formulas and thus memory taken up by a single cell value is now only 16 bytes instead of 24 (?) bytes in 0.102. Of course there are some other structures around that take up memory as well, but the single cell value is now 16 bytes (I hoped for 8, but not feasible with `double`, `DateTime` and `TimeSpan` as possible cell values - all take up 8 bytes... not enough bits).

The same string in different instances is now not duplicated, but only one instance is used. As seen on following test, it can lead to significant decrease in memory consumption. 250k rows with 10 text rows (same string, different instance): 117 MiB om 0.103 vs 325 MiB in 0.102.1.

## `InsertData` performance 

Insert 250k rows of 10 columns of text and 5 columns of numbers ([gist](https://gist.github.com/jahav/bdc5fe3c90f25544ca6ae1394bbe3561)). 

| Description      |     Rows  |           Columns      | Time/Memory to insert data | Save workbook | Total time/memory | 
|-----------------|-----------|------------------------|----------------------------|------------------------------|---|
| **0.103.0-beta**    |   250 000 | 15 | **1.619 sec / 117 MiB** |  6.343 sec | 477 MiB |
| 0.102.1    |   250 000 | 15 | 7.160 sec / 325 MiB |  6.676 sec | 692 MiB |
 ... (truncated)

## 0.102.3

## What's Changed
* Eliminate a couple of performance killers by @​Pankraty in https://github.com/ClosedXML/ClosedXML/pull/2363

**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.102.2...0.102.3

## 0.102.2

Add a warning about allowed ranges of DocumentFormat.OpenXML see issue #​2220 and PR #​2246.

## What's Changed
* Add dependency version range for DocumentFormat.OpenXml by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2246


**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.102.1...0.102.2

## 0.102.1

SixLabors.Fonts has released version 1.0.0 and some NET Framework projects suddently have errors due to NuGet behavior.

If a project is consuming ClosedXML through `package.config` instead of [`PackageReference` style projects](https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files), the NuGet will resolve version 1.0.0 instead of declared beta19 dependency. SixLabors.Fonts has API changes and thus it will start to throw `MissingMethodException`s.

The issue should only affect net framework projects, not dotnet core that use `PackageReference` style by default.

## What's Changed
* Update SixLabors.Fonts dependency to version 1.0.0 by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2149

**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.102.0...0.102.1

## 0.102.0

# Breaking changes
Please read migration guide from [0.101 to 0.102](https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.102.html). The key ones changes are:
* `IXLCell` is now a proxy to a sparse array and a new proxy is created each time it is requested by user code. `Object.ReferenceEquals(ws.Cell("A1"), ws.Cell("A1"))` now evaluates to `false` (used to be `true`)
* `IXLWorksheet AddWorksheet(DataTable dataTable)` and `IXLWorksheet AddWorksheet(DataTable dataTable, string sheetName)` now use different name for the created table.

# Significant changes 

## Replaced cell storage engine (#​1969)

The cells in a workbook used to be stored in a `Dictionary<int, Dictionary<XLCell>>`. That has several significant drawbacks and the storage has been replaced with a sparse arrays of individual slices (basically a sparse array containing a specific part of a cell).

![slices](https://github.com/ClosedXML/ClosedXML/assets/7634052/83bbcd45-13c9-4e01-be82-3410ec0f60b0)

Key benefits (in long term):
* Decrease in memory consumption - sparse arrays don't use values that aren't use, from esoteric OLAP cube id to styles. 
* Bulk operations - there was pretty much no way to optimize bulk operations. Clear - go through each cell. With sparse arrays, ClosedXML can operate on pices of an array (e.g. preallocate for large inserts, clear an area).
* Most operations use only data from a slice (e.g. setting a formula doesn't have to check all cells, only those that contain formula). Due to nature of sparse array of a slice, I only need to go through cells that contains actually useful content.
* Easier insertion/deletion of rows. XLCell originally contain an address and when a row was inserted, I had to go though all cells and fix address (+ 20 other things). 

Other than memory, it's a potential for the future. Replacing a storage engine is not simple and pretty much everything uses `XLCell` adapter.

An example of different for 500k rows of value only cells ([gist](https://gist.github.com/jahav/505d679ebc5b06a1adb1901498ae1b46)). About 200MB vs 900MB.
![image](https://user-images.githubusercontent.com/7634052/241558453-816e64f3-e698-4e7b-b7df-8e126ad8725a.png)
![image](https://github.com/ClosedXML/ClosedXML/assets/7634052/00e93a5f-d844-4486-98bd-c36cfde5f7ad)

## Embedded fonts (#​2106)

Default graphic engine of ClosedXML now contains an embedded font. That should be a quality of life improvement for users on Linux and other non-Windows environment who encountered 

> Unable to find font font name or fallback font fallback font name. Install missing fonts or specify a different fallback font through ‘LoadOptions.DefaultGraphicEngine = new DefaultGraphicEngine(“Fallback font name”)’.. 

The embedded font is an absolute bare bones Carlito font (though with a different name to avoid collision with the real one).

See doc for workflow of font selection: https://closedxml.readthedocs.io/en/latest/features/graphic-engine.html#fallback-and-embedded-font

## Array formulas

A basic support for array formulas has been added. You can create array formula through `IXLRangeBase` object.
`csharp
ws.Range("B2:D3").FormulaArrayA1 = "B1:D1*POWER(1+A2:A3, 2)";
`
![image](https://github.com/ClosedXML/ClosedXML/assets/7634052/62efdb51-daaf-4b3b-a778-758858b991d6)

For more info, see doc: https://closedxml.readthedocs.io/en/latest/features/formulas.html#array-formulas

## Refactored pivot source (#​1238)

The ancient PR from 2019 has been finally fixed and merged. It doesn't really add very useful features (multiple pivot tables don't have to have individual data store files in a xlsx file), but it is a big step to represent pivot cache data in a workbook. That is pretty much required to do anything useful with pivot tables.

The biggest visible improvement is that there is at least some very basic documentation about pivot tables https://closedxml.readthedocs.io/en/latest/features/pivot-tables.html
 ... (truncated)

## 0.102.0-rc

# Significant changes 

## Replaced cell storage engine (#​1969)

The cells in a workbook used to be stored in a `Dictionary<int, Dictionary<XLCell>>`. That has several significant drawbacks and the storage has been replaced with a sparse arrays of individual slices (basically a sparse array containing a specific part of a cell).

![slices](https://github.com/ClosedXML/ClosedXML/assets/7634052/83bbcd45-13c9-4e01-be82-3410ec0f60b0)

Key benefits (in long term):
* Decrease in memory consumption - sparse arrays don't use values that aren't use, from esoteric OLAP cube id to styles. 
* Bulk operations - there was pretty much no way to optimize bulk operations. Clear - go through each cell. With sparse arrays, ClosedXML can operate on pices of an array (e.g. preallocate for large inserts, clear an area).
* Most operations use only data from a slice (e.g. setting a formula doesn't have to check all cells, only those that contain formula). Due to nature of sparse array of a slice, I only need to go through cells that contains actually useful content.
* Easier insertion/deletion of rows. XLCell originally contain an address and when a row was inserted, I had to go though all cells and fix address (+ 20 other things). 

Other than memory, it's a potential for the future. Replacing a storage engine is not simple and pretty much everything uses `XLCell` adapter.

An example of different for 500k rows of value only cells ([gist](https://gist.github.com/jahav/505d679ebc5b06a1adb1901498ae1b46)). About 200MB vs 900MB.
![image](https://user-images.githubusercontent.com/7634052/241558453-816e64f3-e698-4e7b-b7df-8e126ad8725a.png)
![image](https://github.com/ClosedXML/ClosedXML/assets/7634052/00e93a5f-d844-4486-98bd-c36cfde5f7ad)

## Embedded fonts (#​2106)

Default graphic engine of ClosedXML now contains an embedded font. That should be a quality of life improvement for users on Linux and other non-Windows environment who encountered 

> Unable to find font font name or fallback font fallback font name. Install missing fonts or specify a different fallback font through ‘LoadOptions.DefaultGraphicEngine = new DefaultGraphicEngine(“Fallback font name”)’.. 

The embedded font is an absolute bare bones Carlito font (though with a different name to avoid collision with the real one).

See doc for workflow of font selection: https://closedxml.readthedocs.io/en/latest/features/graphic-engine.html#fallback-and-embedded-font

## Array formulas

A basic support for array formulas has been added. You can create array formula through `IXLRangeBase` object.
`csharp
ws.Range("B2:D3").FormulaArrayA1 = "B1:D1*POWER(1+A2:A3, 2)";
`
![image](https://github.com/ClosedXML/ClosedXML/assets/7634052/62efdb51-daaf-4b3b-a778-758858b991d6)

For more info, see doc: https://closedxml.readthedocs.io/en/latest/features/formulas.html#array-formulas

## Refactored pivot source (#​1238)

The ancient PR from 2019 has been finally fixed and merged. It doesn't really add very useful features (multiple pivot tables don't have to have individual data store files in a xlsx file), but it is a big step to represent pivot cache data in a workbook. That is pretty much required to do anything useful with pivot tables.

The biggest visible improvement is that there is at least some very basic documentation about pivot tables https://closedxml.readthedocs.io/en/latest/features/pivot-tables.html

# Misc info & next release

Not really something that is useful at this moment, but there has been significant work done on a replacement of a XLParser (https://github.com/ClosedXML/ClosedXML.Parser).

 ... (truncated)

## 0.101.0

Mostly speed improvements, but some cool and nifty improvements, see changelog below.

Other than some enums being changed from int to byte, and a new method on `IXLGraphicEngine` interface there should be no breaking changes in the release (see https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.101.html).

# Worksheet saving (#​1838)
Saving of cells in a worksheet has been significantly improved. As an example, a file of 100k rows and 44 columns (see [gist](https://gist.github.com/jahav/e9d8c5cf2830fb1754101cb0a66f7e36)) took 38 seconds to save in 0.100.3, but only 17 seconds in 0.101-rc . 

![Speedup-0 101-rc](https://user-images.githubusercontent.com/7634052/229314296-ecf27931-4d74-43f5-be58-cfac97978a43.png)
![Speedup-0 100 3](https://user-images.githubusercontent.com/7634052/229314297-1f857ed2-1f86-4ac2-bc07-9d9d8f72d069.png)

# Adjust to content (#​1991)
Adjust to content has been refactored and it now calculates size of text by counting glyphs. Originally, we asked SixLabors.Fonts library to calculate it, but it is really slow (it has to deal with all possible typographic options, like having rtl and ltr text on same line).

It is faster to just use glyph size, plus I am pretty sure Excel also calculates width/height of a cell that way (likely legacy from earlier 90s version).

Time to run `AdjustToContent` using a sample of 1000 rows.

|Run# | 0.96.0|0.100.3  |0.101-rc     | 
|-----|--------|---------|-------|
|1    | 168 ms|1203 ms | 1674 ms| 
|2    |   4 ms|568 ms |   31 ms|  
|3    |   4 ms|551 ms |   25 ms|  
|4    |   4 ms|540 ms |   26 ms|  
|5    |   3 ms|544 ms |   25 ms|  
|6    |   3 ms|550 ms |   26 ms|  
|7    |   4 ms|556 ms |   46 ms|  
|8    |      3 ms|556 ms |28 ms|  
|9    |      4 ms|541 ms |23 ms|  
|10   |   3 ms|535 ms |   23 ms|  

# 

# Changelog

## Performance improvements
* Improve performance when opening workbook by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1998
* Change ExpressionCache to use ConditionalWeakTable by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1968
* Separate XLCellFormula out of XLCell by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1972
* Don't allocate XLCellFormula for each XLCell by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2043
* Speedup adjust to content by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2037
* Save SheetData through XmlWriter by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1984
* Reimplement SEARCH function and add wildcard struct by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2007

## Features
* Calculate default column width from default font. by @​nakamura2000 in https://github.com/ClosedXML/ClosedXML/pull/1954
* Add ability to load and save data table formulae by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1974
* ROWS and COLUMNS functions by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1981

## Cleanup updates
* Remove unnecessary reference to Microsoft.CSharp by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1999
 ... (truncated)

## 0.101.0-rc

Mostly speed improvements, but some cool and nifty improvements, see changelog below. Prod release will be 1 week after RC.

Other than some enums being changed from int to byte, and a new method on `IXLGraphicEngine` interface there should be no breaking changes in the release (see https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.101.html).

# Worksheet saving (#​1838)
Saving of cells in a worksheet has been significantly improved. As an example, a file of 100k rows and 44 columns (see [gist](https://gist.github.com/jahav/e9d8c5cf2830fb1754101cb0a66f7e36)) took 38 seconds to save in 0.100.3, but only 17 seconds in 0.101-rc . 

![Speedup-0 101-rc](https://user-images.githubusercontent.com/7634052/229314296-ecf27931-4d74-43f5-be58-cfac97978a43.png)
![Speedup-0 100 3](https://user-images.githubusercontent.com/7634052/229314297-1f857ed2-1f86-4ac2-bc07-9d9d8f72d069.png)

# Adjust to content (#​1991)
Adjust to content has been refactored and it now calculates size of text by counting glyphs. Originally, we asked SixLabors.Fonts library to calculate it, but it is really slow (it has to deal with all possible typographic options, like having rtl and ltr text on same line).

It is faster to just use glyph size, plus I am pretty sure Excel also calculates width/height of a cell that way (likely legacy from earlier 90s version).

Time to run `AdjustToContent` using a sample of 1000 rows.

|Run# | 0.96.0|0.100.3  |0.101-rc     | 
|-----|--------|---------|-------|
|1    | 168 ms|1203 ms | 1674 ms| 
|2    |   4 ms|568 ms |   31 ms|  
|3    |   4 ms|551 ms |   25 ms|  
|4    |   4 ms|540 ms |   26 ms|  
|5    |   3 ms|544 ms |   25 ms|  
|6    |   3 ms|550 ms |   26 ms|  
|7    |   4 ms|556 ms |   46 ms|  
|8    |      3 ms|556 ms |28 ms|  
|9    |      4 ms|541 ms |23 ms|  
|10   |   3 ms|535 ms |   23 ms|  

# 

# Changelog

## Performance improvements
* Improve performance when opening workbook by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1998
* Change ExpressionCache to use ConditionalWeakTable by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1968
* Separate XLCellFormula out of XLCell by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1972
* Don't allocate XLCellFormula for each XLCell by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2043
* Speedup adjust to content by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2037
* Save SheetData through XmlWriter by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1984
* Reimplement SEARCH function and add wildcard struct by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/2007

## Features
* Calculate default column width from default font. by @​nakamura2000 in https://github.com/ClosedXML/ClosedXML/pull/1954
* Add ability to load and save data table formulae by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1974
* ROWS and COLUMNS functions by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1981

## Cleanup updates
* Remove unnecessary reference to Microsoft.CSharp by @​lahma in https://github.com/ClosedXML/ClosedXML/pull/1999
 ... (truncated)

## 0.100.3

Fix a regression where some types of numbers were inserted as text by InsertData/InsertTable API.

// Only int and double were inserted as numbers, now all types are
cell.InsertData(new object[] { (sbyte)1, (byte)2, (short)3, (ushort)4, (uint)6, (long)7, (ulong)8, 15f, 17m });


## What's Changed
* Insert all number types as numbers by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1967


**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.100.2...0.100.3

## 0.100.2

# Nullable conversions

Second fix for https://github.com/ClosedXML/ClosedXML/releases/tag/0.100.0.

Added conversion for nullable numbers/DateTime/TimeSpan to `XLCellValue`. Null values will be converted to `Blank.Value` in the `XLCellValue`. There is no value in having user code littered by `cell.Value = nullableNumber ?? Blank.Value`. 

Null strings assigned to XLCellValue will also be converted to `Blank.Value` (unlike exception from 0.100).

## What's Changed
* Add conversion for nullable numbers/datetime/timespan by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1963


**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.100.1...0.100.2

## 0.100.1

This is a quick improvement for https://github.com/ClosedXML/ClosedXML/releases/tag/0.100.0.
It adds an implicit conversion for decimal numbers to `XLCellValue`, so users who generate workbooks with decimal number don't have to add explicit casting from decimal to double everywhere.

## What's Changed
* Add implicit conversion from decimal to double for XLCellValue.  by @​jahav in https://github.com/ClosedXML/ClosedXML/pull/1961


**Full Changelog**: https://github.com/ClosedXML/ClosedXML/compare/0.100.0...0.100.1

## 0.100.0

# Clean Break

These are release notes for a version 0.100. We skipped a few version since the last release (0.97), because 0.100 should denote a major change at the very heart of ClosedXML. Not as clean break as I hoped, but close enough.

The list of all things that were changed from 0.97 to 0.100 is at the **migration guide** at the https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.100.html

This is more like list of you should upgrade despite breaking changes :)

# Memory consumption during big was decreased

Memory consumption during saving of large data workbooks was significantly improved. Originally, ClosedXML workbook representation was converted to DocumentFomrat.OpenXML DOM representation and the DOM was then saved. Instead of creating whole DOM, sheet data (=cell values) are now directly streamed to the output file and aren't included in the DOM.

To demonstrate difference, see the before and after memory consumption of a report that generated 30 000 rows, 45 columns. Memory consumption has decreased from **2.08** GiB 🡆 **0.8** GiB. 

Save cells and strings through DOM: **2.08 GiB** 
![1874-dtoMemory-save-30k-text-DOM](https://user-images.githubusercontent.com/7634052/208317997-24765ff2-17c2-4272-9b66-5d98fe08c089.png)

Save cell and strings through streaming: **0.8 GiB**
![1874-dtoMemory-save-30k-text-streaming](https://user-images.githubusercontent.com/7634052/208318008-2df5f259-0ffd-48fe-8f44-272d173e415f.png)

The purple area are bytes of uncompressed package zip stream.

# Cell value is now strongly typed

`IXLCell.Value` and `IXLCellValue.CachedValue` have now type `XLCellValue`. At the core, xlsx consists of addressable cells with a functions that transform a set of values in source cells to different values in target cells. Is is really important to represent potential values of cells by a sane type. All other things, pivot tables, auto filter, graphs rely on this premise.

Cell value has been represented as string text and a value. The string depended on the value, e.g. *0*/*1* for boolean. That has been the case since the beginning of the ClosedXML project (see the [original XLCell](https://github.com/ClosedXML/ClosedXML/blob/29e7f01e74c20dd19f0366ad4a190615e12772f2/ClosedXML/ClosedXML/ClosedXML/Excel/XLCell.cs)). The value was also returned as an `Object`.
This approach has several drawbacks

* `Object` is not suitable representation of cell value. User had no idea what kind of values could be returned as a cell value. Everything could also break down, if a new type would be returned (e.g. `XLError`).
* Setter could accept different types that the getter returned. E.g. it was possible to set cell value to a `IXLColumn`.
* Values were always boxed/unboxed. That is not  a problem for small amount of data, but it is not great for large workbooks.
* It caused an potentially buggy behavior in other places of the ClosedXML.

Value of a cell is not represented by a `XLCellValue` structure. It is basically a union of one of possible types that can be value of a cell:
* blank
* boolean
* number
* text
* error
* datetime - basically number representing serial datetime, use serial datetime.
* duration - basically number representing serial datetime, use serial datetime

Since datetime and duration are basically masqaraded number, you can use `XLCellValue.GetUnifiedNumber()` to get a backing number, no matter if the type is number, datetime and duration.

The structure contains implicit operators, as well as other methods to make transaction as seamless as possible

```csharp
// Will use an implicit cast operator to convert string to XLCellValue and pass it to the Value setter
ws.Cell("A1").Value = "Text";
 ... (truncated)

## 0.97.0

Project has been on hiatus for a while, but things are now moving forward.
See full list of changes at https://github.com/ClosedXML/ClosedXML/milestone/17?closed=1 

# Breaking changes
* Methods that were depending on the `System.Common.Drawing` were removed (use another overload):
* * `IXLPictures.AddPicture(Bitmap bitmap)`
* * `IXLPictures.AddPicture(Bitmap bitmap, String name)`
* * `IXLWorksheet.AddPicture(Bitmap bitmap)`
* * `IXLWorksheet.AddPicture(Bitmap bitmap, string name)`
* Date/time formulas (NOW(), HOUR()...) returns serial date-time, cell is no longer implicitly `XLDataType.DateTime` or `XLDataType.TimeSpan`. The DataType has to be set explicitely.
* CalcEngine can now return XLError on error, not a CalcEngineException exception.
* Non-windows environments: ClosedXML must be configured an available fallback font for the graphic engine, otherwise an will throw an exception (the exception message contains info what to do). System.Drawing.Common had some kind of logic, now it has to be done manually.

# Improvements
## System.Drawing.Common removal (#​1805)
We have removed a System.Drawing.Common dependency, it was deprecated and throws runtime exception when called on non-windows environments. All complexity has been hidden behind an interface `IXLGraphicEngine` and a default implementation `DefaultGraphicEngine` in the `ClosedXML.Graphics namespace. The default engine uses [SixLabors.Fonts](https://github.com/SixLabors/Fonts) library for font measurements. You can read more on the [Graphic Engine](https://github.com/ClosedXML/ClosedXML/wiki/Graphic-Engine) wiki page.

On non-windows environment, it will be necessary to specify a default font. Use this code
```csharp
// All workbooks created later will use the engine with a fallback font DejaVu Sans
LoadOptions.DefaultGraphicsEngine = new DefaultGraphicEngine("DejaVu Sans"); // or Tahoma or any other font that is installed

Use XLParser to parse formulas

ClosedXML has used a handcrafted parser for a while. The parse could parse a simple formulas, but a lot of features were out of its grasp (e.g. arrays, references to other worksheets, operations on references and so much more). We have replaced the original the original parser with the XLParser to facilitate a more powerful formulas.

You can try the parsing yourself on an online demo page: https://xlparser.perfectxl.nl/demo/

Through slower than the original parser, we are working with upstream to improve performance (spreadsheetlab/XLParser#163, spreadsheetlab/XLParser#161). Not-so-close future of CalcEngine is also multi threaded.

CalcEngine redesign

CalcEngine has been half-rewritten. It can now correctly represent all Excel types (e.g. Error is now a value, not an an exception) and perform operations on them (e.g. reference unions, comparisons work as they should).

As an example, SUM of two areas that overlap should count overlapping cells twice, thus the result should be 12, not 9.

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.Range(1, 1, 3, 3).SetValue(1);
var sum = ws.Evaluate("SUM((A1:B3,B1:C3))");
Console.WriteLine($"Result of a SUM function: {sum}");

Result of a SUM function: 12

image

A major change has been implicit intersections in the semantic of 2019 excel (Excel 2021 and 365 already support dynamic array formulas):

using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
 ... (truncated)

## 0.96.0

See full list of changes at:
https://github.com/ClosedXML/ClosedXML/pulls?q=is%3Apr+milestone%3Av0.96+is%3Aclosed

# Breaking changes
- [ClosedXML](https://www.nuget.org/packages/ClosedXML/) NuGet package is now signed. [ClosedXML.Signed](https://www.nuget.org/packages/ClosedXML.Signed/) is deprecated. #​1552 
- #​1396 
    * `IXLCell.Hyperlink` removed; use `GetHyperlink()` to get an existing hyperlink or to create a new one if it does not exist; instead of property setter, use `SetHyperlink()`; to replace the existing hyperlink with a fresh one, use `CreateHyperlink()`;
    * `IXLCell.DataValidation` removed; use `GetDataValidation()`;
    * `IXLCell.NewDataValidation` removed; use `CreateDataValidation()`;
    * `IXLCell.Comment` removed; use `GetComment()` to access the existing comment or to create a new one if it does not exist; use `CreateComment()` to replace the existing comment with the fresh one;
    * `IXLCell.RichText` removed; use `GetRichText()` to access the existing rich text or to create a new one if it does not exist; use `CreateRichText()` to replace the existing rich text with the fresh one.


Commits viewable in [compare view](https://github.com/ClosedXML/ClosedXML/commits/0.105.0).
</details>

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ClosedXML&package-manager=nuget&previous-version=0.95.4&new-version=0.105.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

---
updated-dependencies:
- dependency-name: ClosedXML
  dependency-version: 0.105.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
@dependabot dependabot bot added .NET Pull requests that update .NET code dependencies Pull requests that update a dependency file labels Aug 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants