Initial commit of the ClosedXML library

Establishes the foundational structure, core Excel functionality, and tooling.

- Implements base components for cells, ranges, columns, and rows.
- Integrates a custom calculation engine with a wide range of Excel functions.
- Adds comprehensive support for styling, conditional formatting, data validation, comments, pictures, and charts.
- Configures build setup, project metadata (NuGet), and developer guidelines.
- Includes editor and Git attributes for consistent code style and line endings.
This commit is contained in:
Thom Lamb
2026-06-23 11:02:53 -05:00
parent 28bc05cf54
commit 2cd6df6481
1092 changed files with 97270 additions and 408 deletions
@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net40;net46</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<Version>0.95.4</Version>
<NoWarn>$(NoWarn);NU1605</NoWarn>
<Configurations>Debug;Release;Release.Signed</Configurations>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<DefineConstants>$(DefineConstants);_NETSTANDARD_;_NETSTANDARD2_0_</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net40' ">
<DefineConstants>$(DefineConstants);_NETFRAMEWORK_;_NET40_</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net46' ">
<DefineConstants>$(DefineConstants);_NETFRAMEWORK_;_NET46_</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net46'">
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
<None Update="test.xlsx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClosedXML\ClosedXML.csproj" />
</ItemGroup>
</Project>
+89
View File
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace ClosedXML_Sandbox
{
public class OneRow
{
[Display(Name = "Col01")]
public int Col01 { get; set; }
[Display(Name = "Col02")]
public string Col02 { get; set; }
[Display(Name = "Col03")]
public DateTime? Col03 { get; set; }
[Display(Name = "Col04")]
public TimeSpan? Col04 { get; set; }
[Display(Name = "Col05")]
public TimeSpan? Col05 { get; set; }
[Display(Name = "Col06")]
public TimeSpan? Col06 { get; set; }
[Display(Name = "Col07")]
public TimeSpan? Col07 { get; set; }
[Display(Name = "Col08")]
public TimeSpan? Col08 { get; set; }
[Display(Name = "Col09")]
public string Col09 { get; set; }
[Display(Name = "Col10")]
public decimal Col10 { get; set; }
[Display(Name = "Col11")]
public string Col11 { get; set; }
[Display(Name = "Col12")]
public bool Col12 { get; set; }
[Display(Name = "Col13")]
public bool Col13 { get; set; }
[Display(Name = "Col14")]
public string Col14 { get; set; }
[Display(Name = "Col15")]
public bool Col15 { get; set; }
[Display(Name = "Col16")]
public string Col16 { get; set; }
[Display(Name = "Col17")]
public string Col17 { get; set; }
[Display(Name = "Col18")]
public DateTime? Col18 { get; set; }
[Display(Name = "Col19")]
public string Col19 { get; set; }
[Display(Name = "Col20")]
public string Col20 { get; set; }
[Display(Name = "Col21")]
public string Col21 { get; set; }
[Display(Name = "Col22")]
public string Col22 { get; set; }
[Display(Name = "Col23")]
public string Col23 { get; set; }
[Display(Name = "Col24")]
public bool Col24 { get; set; }
[Display(Name = "Col25")]
public int? Col25 { get; set; }
[Display(Name = "Col26")]
public string Col26 { get; set; }
}
}
+170
View File
@@ -0,0 +1,170 @@
using ClosedXML.Excel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
namespace ClosedXML_Sandbox
{
internal class PerformanceRunner
{
public static void TimeAction(Action action)
{
var stopwatch = Stopwatch.StartNew();
action();
Console.WriteLine("Action done in " + stopwatch.Elapsed);
}
private const int rowCount = 5000;
public static void RunInsertTable()
{
var rows = new List<OneRow>();
for (int i = 0; i < rowCount; i++)
{
var row = GenerateRow<OneRow>();
rows.Add(row);
}
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sheet 1");
worksheet.Cell(1, 1).InsertTable(rows);
CreateMergedCell(worksheet);
worksheet.Columns().AdjustToContents();
EmulateSave(workbook);
}
public static void OpenTestFile()
{
using (var wb = new XLWorkbook("test.xlsx"))
{
wb.RecalculateAllFormulas();
var ws = wb.Worksheets.First();
var cell = ws.FirstCellUsed();
Console.WriteLine(cell.Value);
}
}
private static void CreateMergedCell(IXLWorksheet worksheet)
{
worksheet.Cell(rowCount + 2, 1).Value = "Merged cell";
var range = worksheet.Range(rowCount + 2, 1, rowCount + 2, 2);
range.Row(1).Merge();
}
private static void EmulateSave(XLWorkbook workbook)
{
using (MemoryStream memoryStream = new MemoryStream())
{
workbook.SaveAs(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
Console.WriteLine("Total bytes = " + memoryStream.ToArray().Length);
}
}
private static Random rnd = new Random();
private static T GenerateRow<T>() where T : new()
{
var row = new T();
var rowProps = row.GetType().GetProperties();
var strings = rowProps.Where(p => p.PropertyType == typeof(string));
var decimals = rowProps.Where(p => p.PropertyType == typeof(decimal));
var ints = rowProps.Where(p => p.PropertyType == typeof(int) || p.PropertyType == typeof(int?));
var dates = rowProps.Where(p => p.PropertyType == typeof(DateTime?));
var timeSpans = rowProps.Where(p => p.PropertyType == typeof(TimeSpan?));
var booleans = rowProps.Where(p => p.PropertyType == typeof(bool));
// Format strings
var tmpString = new StringBuilder();
var tmpStringLength = rnd.Next(5, 50);
for (int x = 0; x <= tmpStringLength; x++)
{
tmpString.Append((char)(rnd.Next(48, 120)));
}
foreach (var str in strings)
{
str.SetValue(row, tmpString.ToString(), null);
}
// Format decimals
var tmpDec = (decimal)(rnd.Next(-10000, 100000) / (Math.Pow(10.0, rnd.Next(1, 4))));
foreach (var dec in decimals)
{
dec.SetValue(row, tmpDec, null);
}
// Format ints
var tmpInt = rnd.Next(-1000, 10000);
foreach (var intValue in ints)
{
intValue.SetValue(row, tmpInt, null);
}
// Format dates
var tmpDate = new DateTime(2012, 1, 1, 1, 1, 1);
tmpDate = tmpDate.AddSeconds(rnd.Next(-10000, 100000));
foreach (var dt in dates)
{
dt.SetValue(row, tmpDate, null);
}
// Format timespans
var tmpTimespan = new TimeSpan(rnd.Next(1, 24), rnd.Next(1, 60), rnd.Next(1, 60));
foreach (var ts in timeSpans)
{
ts.SetValue(row, tmpTimespan, null);
}
// Format booleans
var tmpBool = (rnd.Next(0, 2) > 0);
foreach (var bl in booleans)
{
bl.SetValue(row, tmpBool, null);
}
return row;
}
public static void PerformHeavyCalculation()
{
int rows = 200;
int columns = 200;
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var lastColumnLetter = sheet.Column(columns).ColumnLetter();
for (int i = 1; i <= rows; i++)
{
for (int j = 1; j <= columns; j++)
{
if (i == 1)
{
sheet.Cell(i, j).FormulaA1 = string.Format("=ROUND({0}*SIN({0}),2)", j);
}
else
{
sheet.Cell(i, j).FormulaA1 = string.Format("=SUM({0}$1:{0}{1})/SUM($A{1}:${2}{1})",
sheet.Column(j).ColumnLetter(), i - 1, lastColumnLetter); // i.e. for K8 there will be =SUM(K$1:K7)/SUM($A7:$GR7)
}
}
}
var cells = sheet.CellsUsed();
var sum1 = cells.Sum(cell => (double)cell.Value);
Console.WriteLine("Total sum: {0:N2}", sum1);
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
using System;
namespace ClosedXML_Sandbox
{
internal static class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Running {0}", nameof(PerformanceRunner.OpenTestFile));
PerformanceRunner.TimeAction(PerformanceRunner.OpenTestFile);
Console.WriteLine();
// Disable this block by default - I don't use it often
#if false
Console.WriteLine("Running {0}", nameof(PerformanceRunner.RunInsertTable));
PerformanceRunner.TimeAction(PerformanceRunner.RunInsertTable);
Console.WriteLine();
Console.WriteLine("Running {0}", nameof(PerformanceRunner.PerformHeavyCalculation));
PerformanceRunner.TimeAction(PerformanceRunner.PerformHeavyCalculation);
Console.WriteLine();
#endif
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
}
}
+17
View File
@@ -0,0 +1,17 @@
#if _NET40_
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace ClosedXML_Sandbox
{
internal static class ReflectionExtensions
{
public static void SetValue(this PropertyInfo info, object obj, object value)
{
info.SetValue(obj, value, null);
}
}
}
#endif
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Binary file not shown.