From 2a8e4d435e753d7a4e42b3165513e345f50d2da5 Mon Sep 17 00:00:00 2001 From: Leonid Salavatov Date: Fri, 2 Feb 2024 21:22:43 +0300 Subject: [PATCH] 2.4.3 --- ArrayToExcel/ArrayToExcel.csproj | 6 ++-- ArrayToExcel/CellDate.cs | 41 +++++++++++++++++++++++++ ArrayToExcel/CellDefault.cs | 37 ++++++++-------------- ArrayToExcel/CellFormula.cs | 10 +++--- ArrayToExcel/CellHyperlink.cs | 2 +- ArrayToExcel/CellPercent.cs | 2 +- ArrayToExcel/CellText.cs | 8 ++--- ArrayToExcel/ExcelBuilder.cs | 24 ++++++++++----- ArrayToExcel/Styles.cs | 12 ++++++++ Examples/Example.ConsoleApp/Program.cs | 7 +++-- Examples/Example.ConsoleApp/SomeItem.cs | 2 +- 11 files changed, 102 insertions(+), 49 deletions(-) create mode 100644 ArrayToExcel/CellDate.cs create mode 100644 ArrayToExcel/Styles.cs diff --git a/ArrayToExcel/ArrayToExcel.csproj b/ArrayToExcel/ArrayToExcel.csproj index 226fa89..c990d0f 100644 --- a/ArrayToExcel/ArrayToExcel.csproj +++ b/ArrayToExcel/ArrayToExcel.csproj @@ -6,9 +6,9 @@ enable True ..\ArrayToExcel.snk - 2.4.2 - 2.4.2 - 2.4.2 + 2.4.3 + 2.4.3 + 2.4.3 Leonid Salavatov Leonid Salavatov 2024 diff --git a/ArrayToExcel/CellDate.cs b/ArrayToExcel/CellDate.cs new file mode 100644 index 0000000..d137234 --- /dev/null +++ b/ArrayToExcel/CellDate.cs @@ -0,0 +1,41 @@ +using DocumentFormat.OpenXml.Spreadsheet; +using System; + +namespace ArrayToExcel; + +public class CellDate : ICellValue +{ + public CellDate(DateTime? dateTime, bool dateOnly = false) + { + _value = dateTime?.ToString(_dateTimeFormat); + _dateOnly = dateOnly; + } + + public CellDate(DateTimeOffset? dateTime, bool dateOnly = false) + { + _value = dateTime?.ToString(_dateTimeFormat); + _dateOnly = dateOnly; + } + +#if NET6_0_OR_GREATER + public CellDate(DateOnly? date) + { + _value = date?.ToString(_dateFormat); + _dateOnly = true; + } + + static readonly string _dateFormat = "o"; +#endif + + static readonly string _dateTimeFormat = "s"; + readonly string? _value; + readonly bool _dateOnly; + + public virtual void Apply(Cell cell, uint row) + { + + cell.CellValue = new(_value ?? string.Empty); + cell.DataType = CellValues.Date; + cell.StyleIndex = _dateOnly ? Styles.Date : Styles.DateTime; + } +} diff --git a/ArrayToExcel/CellDefault.cs b/ArrayToExcel/CellDefault.cs index baed339..e70abf5 100644 --- a/ArrayToExcel/CellDefault.cs +++ b/ArrayToExcel/CellDefault.cs @@ -14,32 +14,24 @@ internal static void Apply(Cell cell, object? value) { cell.CellValue = GetCellValue(value); cell.DataType = GetCellType(value); - cell.StyleIndex = cell.DataType == CellValues.Date ? 2 : 4u; + cell.StyleIndex = Styles.Default; } static CellValue GetCellValue(object? value) { if (value == null) return new(); - var type = value.GetType(); + if (value is bool boolVal) + return new(_boolVals[boolVal ? 1 : 0]); - if (type == typeof(bool)) - return new((bool)value ? _boolVals[1] : _boolVals[0]); + if (value is double doubleVal) + return new(doubleVal.ToString(_cultureInfo)); - if (type == typeof(DateTime)) - return new(((DateTime)value).ToString(_dateFormat, _cultureInfo)); + if (value is decimal decimalVal) + return new(decimalVal.ToString(_cultureInfo)); - if (type == typeof(DateTimeOffset)) - return new(((DateTimeOffset)value).ToString(_dateFormat, _cultureInfo)); - - if (type == typeof(double)) - return new(((double)value).ToString(_cultureInfo)); - - if (type == typeof(decimal)) - return new(((decimal)value).ToString(_cultureInfo)); - - if (type == typeof(float)) - return new(((float)value).ToString(_cultureInfo)); + if (value is float floatVal) + return new(floatVal.ToString(_cultureInfo)); return new(NormCellText(value.ToString()!)); } @@ -52,17 +44,15 @@ internal static string NormCellText(string value) static CellValues GetCellType(object? value) { - var type = value?.GetType() ?? typeof(object); + if (value == null) + return CellValues.String; - if (type == typeof(bool)) + if (value is bool) return CellValues.Boolean; - if (_numericTypes.Contains(type)) + if (_numericTypes.Contains(value.GetType())) return CellValues.Number; - if (type == typeof(DateTime) || type == typeof(DateTimeOffset)) - return CellValues.Date; - return CellValues.String; } @@ -78,7 +68,6 @@ static CellValues GetCellType(object? value) typeof(float)]; static readonly CultureInfo _cultureInfo = CultureInfo.GetCultureInfo("en-US"); - static readonly string _dateFormat = "s"; static readonly string[] _boolVals = ["0", "1"]; const int _maxCellText = 32767; diff --git a/ArrayToExcel/CellFormula.cs b/ArrayToExcel/CellFormula.cs index 3dd4b48..9be8413 100644 --- a/ArrayToExcel/CellFormula.cs +++ b/ArrayToExcel/CellFormula.cs @@ -3,14 +3,14 @@ namespace ArrayToExcel; -public class CellFormula(Func cellText) : ICellValue +public class CellFormula(Func value, bool wrapText = false) : ICellValue { - public CellFormula(Func rowText) : this((row, cell) => rowText(row)) { } - public CellFormula(string text) : this((row, col) => text) { } + public CellFormula(Func value, bool wrapText = false) : this((row, cell) => value(row), wrapText) { } + public CellFormula(string text, bool wrapText = false) : this((row, col) => text, wrapText) { } public virtual void Apply(Cell cell, uint row) { - cell.CellFormula = new DocumentFormat.OpenXml.Spreadsheet.CellFormula(cellText(row, cell.CellReference!)); - cell.StyleIndex = 4; + cell.CellFormula = new DocumentFormat.OpenXml.Spreadsheet.CellFormula(value(row, cell.CellReference!)); + cell.StyleIndex = wrapText ? Styles.WrapText : Styles.Default; } } diff --git a/ArrayToExcel/CellHyperlink.cs b/ArrayToExcel/CellHyperlink.cs index 8922e78..292359d 100644 --- a/ArrayToExcel/CellHyperlink.cs +++ b/ArrayToExcel/CellHyperlink.cs @@ -11,7 +11,7 @@ public CellHyperlink(Uri link, string? text = null) public virtual void Apply(Cell cell, uint row) { cell.CellFormula = new DocumentFormat.OpenXml.Spreadsheet.CellFormula(_format.Value); - cell.StyleIndex = 3; + cell.StyleIndex = Styles.Hyperlink; } readonly Lazy _format = new(() => Format(link, text)); diff --git a/ArrayToExcel/CellPercent.cs b/ArrayToExcel/CellPercent.cs index 9b03d42..590be15 100644 --- a/ArrayToExcel/CellPercent.cs +++ b/ArrayToExcel/CellPercent.cs @@ -7,6 +7,6 @@ public class CellPercent(object? value) : CellDefault(value) public override void Apply(Cell cell, uint row) { base.Apply(cell, row); - cell.StyleIndex = 5; + cell.StyleIndex = Styles.Percentage; } } diff --git a/ArrayToExcel/CellText.cs b/ArrayToExcel/CellText.cs index e9926c8..e9899a7 100644 --- a/ArrayToExcel/CellText.cs +++ b/ArrayToExcel/CellText.cs @@ -3,15 +3,15 @@ namespace ArrayToExcel; -public class CellText(string? value, bool wrap = false) : ICellValue +public class CellText(string? value, bool wrapText = false) : ICellValue { - public virtual void Apply(Cell cell, uint row) => Apply(cell, value, wrap); + public virtual void Apply(Cell cell, uint row) => Apply(cell, value, wrapText); - internal static void Apply(Cell cell, string? value, bool wrap) + internal static void Apply(Cell cell, string? value, bool wrapText) { cell.InlineString = GetInlineString(value ?? string.Empty); cell.DataType = CellValues.InlineString; - cell.StyleIndex = wrap ? 4 : 6u; + cell.StyleIndex = wrapText ? Styles.WrapText : Styles.Default; } static InlineString GetInlineString(string value) diff --git a/ArrayToExcel/ExcelBuilder.cs b/ArrayToExcel/ExcelBuilder.cs index 6d410dc..69dffa5 100644 --- a/ArrayToExcel/ExcelBuilder.cs +++ b/ArrayToExcel/ExcelBuilder.cs @@ -141,17 +141,19 @@ static void AddStyles(WorkbookPart workbookPart) stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()); // header style stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0, FontId = 1, BorderId = 0, FillId = 2, ApplyFill = true }).AppendChild(new Alignment { Horizontal = HorizontalAlignmentValues.Left, Vertical = VerticalAlignmentValues.Center, WrapText = false }); - // datetime style + // default style + stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top, WrapText = false }); + // wraptext style + stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top, WrapText = true }); + // date style stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { ApplyNumberFormat = true, NumberFormatId = 14, FormatId = 0, FontId = 0, BorderId = 0, FillId = 0, ApplyFill = true }).AppendChild(new Alignment { Vertical = VerticalAlignmentValues.Top }); + // datetime style + stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { ApplyNumberFormat = true, NumberFormatId = 22, FormatId = 0, FontId = 0, BorderId = 0, FillId = 0, ApplyFill = true }).AppendChild(new Alignment { Vertical = VerticalAlignmentValues.Top }); // hyperlink style stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0, FontId = 2 }).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top }); - // multiline style - stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top, WrapText = true }); // percentage stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { NumberFormatId = 3453 }).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top }); - // nowrap style - stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()).AppendChild(new Alignment() { Vertical = VerticalAlignmentValues.Top, WrapText = false }); - + stylesPart.Stylesheet.CellFormats.Count = (uint)stylesPart.Stylesheet.CellFormats.ChildElements.Count; stylesPart.Stylesheet.Save(); @@ -164,7 +166,7 @@ static IEnumerable GetRows(IEnumerable items, List columns, b CellReference = GetColReference(i), CellValue = new CellValue(x.Name), DataType = CellValues.String, - StyleIndex = 1, + StyleIndex = Styles.Header, }).ToArray(); var headerRow = new Row() { RowIndex = 1 }; @@ -189,6 +191,14 @@ static Cell GetCell(uint rowIndex, string? cellReference, object? value, bool wr cellValue.Apply(cell, rowIndex); else if (value is string str) CellText.Apply(cell, str, wrapText); + else if (value is DateTime dateTime) + new CellDate(dateTime).Apply(cell, rowIndex); + else if (value is DateTimeOffset dateTimeOffset) + new CellDate(dateTimeOffset).Apply(cell, rowIndex); +#if NET6_0_OR_GREATER + else if (value is DateOnly dateOnly) + new CellDate(dateOnly).Apply(cell, rowIndex); +#endif else if (value is Uri uri) new CellHyperlink(uri).Apply(cell, rowIndex); else diff --git a/ArrayToExcel/Styles.cs b/ArrayToExcel/Styles.cs new file mode 100644 index 0000000..fc63be3 --- /dev/null +++ b/ArrayToExcel/Styles.cs @@ -0,0 +1,12 @@ +namespace ArrayToExcel; + +public static class Styles +{ + public static readonly uint Header = 1; + public static readonly uint Default = 2; + public static readonly uint WrapText = 3; + public static readonly uint Date = 4; + public static readonly uint DateTime = 5; + public static readonly uint Hyperlink = 6; + public static readonly uint Percentage = 7; +} diff --git a/Examples/Example.ConsoleApp/Program.cs b/Examples/Example.ConsoleApp/Program.cs index e180674..b58a37c 100644 --- a/Examples/Example.ConsoleApp/Program.cs +++ b/Examples/Example.ConsoleApp/Program.cs @@ -120,16 +120,17 @@ static void TestTypes() { var items = Enumerable.Range(1, 100).Select(x => new { - String = "1) text text text; \n2) text text text !!!", - WrapText = new CellText("1) text text text; \n2) text text text", wrap: true), + String = " 1) text text text; \n2) text text text !!!", + WrapText = new CellText("1) text text text; \n2) text text text", true), Bool = x % 2 == 0, - NullableBool = x % 2 == 0 ? true : (bool?)null, + NullableBool = x % 2 == 0 ? (bool?)true : null, Int = -x * 100, Uint = (uint)x * 100, Long = (long)x * 100, Double = 1.1d + x, Float = 1.1f + x, Decimal = 1.1m + x, + DateOnly = DateOnly.FromDateTime(DateTime.Now.AddDays(-x)), DateTime = DateTime.Now.AddDays(-x), DateTimeOffset = DateTimeOffset.Now.AddDays(-x), Uri = new Uri($"https://www.google.com/search?q={x}"), diff --git a/Examples/Example.ConsoleApp/SomeItem.cs b/Examples/Example.ConsoleApp/SomeItem.cs index 3f595b2..8ef2072 100644 --- a/Examples/Example.ConsoleApp/SomeItem.cs +++ b/Examples/Example.ConsoleApp/SomeItem.cs @@ -6,6 +6,6 @@ internal class SomeItem { public string Prop1 { get; set; } public int Prop2 { get; set; } - public DateTime Prop3 { get; set; } + public DateTime? Prop3 { get; set; } } }