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:
@@ -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>
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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.
Reference in New Issue
Block a user