From 59486732ee3e05462fc1d9f3bbbda0eaf82e0f9e Mon Sep 17 00:00:00 2001 From: hurles Date: Mon, 2 Dec 2024 22:08:46 +0100 Subject: [PATCH 1/4] converted text styles into flags so we can have multiple some small refactorings --- ...arpExcelArguments.cs => ExcelArguments.cs} | 2 +- .../ExcelColumnDefinitionAttribute.cs | 5 +---- SharpExcel.Models/Results/ExcelAddress.cs | 19 +++++++++++++++++-- SharpExcel.Models/Styling/Text/TextStyle.cs | 9 +++++---- SharpExcel.TestApplication/Program.cs | 4 ++-- .../TestData/TestExportModel.cs | 14 +++++++------- SharpExcel.Tests/ExcelImport.cs | 4 ++-- SharpExcel.Tests/Shared/TestModel.cs | 8 ++++---- .../Abstraction/ISharpExcelSynchronizer.cs | 6 +++--- .../Exporters/BaseSharpExcelSynchronizer.cs | 10 +++++----- SharpExcel/Exporters/TypeMapper.cs | 2 +- .../ExcelSharpCellStyleExtensions.cs | 17 ++++------------- 12 files changed, 52 insertions(+), 48 deletions(-) rename SharpExcel.Models/Arguments/{SharpExcelArguments.cs => ExcelArguments.cs} (92%) diff --git a/SharpExcel.Models/Arguments/SharpExcelArguments.cs b/SharpExcel.Models/Arguments/ExcelArguments.cs similarity index 92% rename from SharpExcel.Models/Arguments/SharpExcelArguments.cs rename to SharpExcel.Models/Arguments/ExcelArguments.cs index c99e636..6185f09 100644 --- a/SharpExcel.Models/Arguments/SharpExcelArguments.cs +++ b/SharpExcel.Models/Arguments/ExcelArguments.cs @@ -5,7 +5,7 @@ namespace SharpExcel.Models.Arguments; /// /// Arguments used for reading/writing excel files /// -public class SharpExcelArguments +public class ExcelArguments { /// /// Name of Excel worksheet to read/write diff --git a/SharpExcel.Models/Attributes/ExcelColumnDefinitionAttribute.cs b/SharpExcel.Models/Attributes/ExcelColumnDefinitionAttribute.cs index d7e5062..f7ac633 100644 --- a/SharpExcel.Models/Attributes/ExcelColumnDefinitionAttribute.cs +++ b/SharpExcel.Models/Attributes/ExcelColumnDefinitionAttribute.cs @@ -6,10 +6,7 @@ namespace SharpExcel.Models.Attributes; /// Name for the column in Excel /// column width to use (-1 means no value (default)) /// optional format string (this will convert the value into a string in Excel) -public class SharpExcelColumnDefinitionAttribute( - string columnName, - int width = -1, - string? format = null) +public class ExcelColumnDefinitionAttribute(string columnName, int width = -1, string? format = null) : Attribute { public string DisplayName { get; set; } = columnName; diff --git a/SharpExcel.Models/Results/ExcelAddress.cs b/SharpExcel.Models/Results/ExcelAddress.cs index 0e6902a..ad24e2f 100644 --- a/SharpExcel.Models/Results/ExcelAddress.cs +++ b/SharpExcel.Models/Results/ExcelAddress.cs @@ -1,12 +1,27 @@ namespace SharpExcel.Models.Results; /// -/// Data structure +/// Data structure for addressing a single cell /// -public struct ExcelAddress +public record struct ExcelAddress { + /// + /// The row number + /// public int RowNumber { get; set; } + + /// + /// Column id + /// public int ColumnId { get; set; } + + /// + /// Column Name + /// public string ColumnName { get; set; } + + /// + /// Header name + /// public string? HeaderName { get; set; } } \ No newline at end of file diff --git a/SharpExcel.Models/Styling/Text/TextStyle.cs b/SharpExcel.Models/Styling/Text/TextStyle.cs index f990986..e559b71 100644 --- a/SharpExcel.Models/Styling/Text/TextStyle.cs +++ b/SharpExcel.Models/Styling/Text/TextStyle.cs @@ -1,9 +1,10 @@ namespace SharpExcel.Models.Styling.Text; +[Flags] public enum TextStyle { - None, - Bold, - Italic, - Underlined + None = 0, + Bold = 1, + Italic = 2, + Underlined = 3 } \ No newline at end of file diff --git a/SharpExcel.TestApplication/Program.cs b/SharpExcel.TestApplication/Program.cs index fc12b75..fac9ecc 100644 --- a/SharpExcel.TestApplication/Program.cs +++ b/SharpExcel.TestApplication/Program.cs @@ -18,7 +18,7 @@ { options.WithDataStyle(SharpExcelCellStyleConstants.DefaultDataStyle); options.WithHeaderStyle(new SharpExcelCellStyle() - .WithTextStyle(TextStyle.Bold) + .WithTextStyle(TextStyle.Bold | TextStyle.Underlined) .WithFontSize(18.0)); options.WithErrorStyle( @@ -46,7 +46,7 @@ async Task RunApp(IServiceProvider services) var exportService = services.GetRequiredService>(); #region write-workbook - var excelArguments = new SharpExcelArguments() + var excelArguments = new ExcelArguments() { SheetName = "Budgets", CultureInfo = CultureInfo.CurrentCulture diff --git a/SharpExcel.TestApplication/TestData/TestExportModel.cs b/SharpExcel.TestApplication/TestData/TestExportModel.cs index c0d4d51..81a8295 100644 --- a/SharpExcel.TestApplication/TestData/TestExportModel.cs +++ b/SharpExcel.TestApplication/TestData/TestExportModel.cs @@ -5,27 +5,27 @@ namespace SharpExcel.TestApplication.TestData; public class TestExportModel { - [SharpExcelColumnDefinition(columnName: "ID", width: 20)] + [ExcelColumnDefinition(columnName: "ID", width: 20)] public int Id { get; set; } - [SharpExcelColumnDefinition(columnName: "Status", width: 15)] + [ExcelColumnDefinition(columnName: "Status", width: 15)] public TestStatus Status { get; set; } [StringLength(10)] - [SharpExcelColumnDefinition(columnName: "First Name", width: 30)] + [ExcelColumnDefinition(columnName: "First Name", width: 30)] public string? FirstName { get; set; } = null!; [StringLength(20)] - [SharpExcelColumnDefinition(columnName: "Last Name", width: 25)] + [ExcelColumnDefinition(columnName: "Last Name", width: 25)] public string? LastName { get; set; } = null!; [Required] - [SharpExcelColumnDefinition(columnName: "Email", width: 50)] + [ExcelColumnDefinition(columnName: "Email", width: 50)] public string? Email { get; set; } = null!; - [SharpExcelColumnDefinition(columnName: "Budget", width: 15)] + [ExcelColumnDefinition(columnName: "Budget", width: 15)] public decimal Budget { get; set; } - [SharpExcelColumnDefinition(columnName: "Department", width: 15)] + [ExcelColumnDefinition(columnName: "Department", width: 15)] public TestDepartment TestDepartment { get; set; } } \ No newline at end of file diff --git a/SharpExcel.Tests/ExcelImport.cs b/SharpExcel.Tests/ExcelImport.cs index c3c0c53..e31fa89 100644 --- a/SharpExcel.Tests/ExcelImport.cs +++ b/SharpExcel.Tests/ExcelImport.cs @@ -22,14 +22,14 @@ public void Setup() [Test] public async Task CreateWorkbookTest() { - var workbook = await _synchronizer.GenerateWorkbookAsync(new SharpExcelArguments(){ SheetName = "TestSheet"}, CreateTestData()); + var workbook = await _synchronizer.GenerateWorkbookAsync(new ExcelArguments(){ SheetName = "TestSheet"}, CreateTestData()); Assert.That(workbook.Worksheets.FirstOrDefault(x => x.Name == "TestSheet") is not null); } [Test] public async Task ReadWorkbookTest() { - var args = new SharpExcelArguments() { SheetName = "TestSheet" }; + var args = new ExcelArguments() { SheetName = "TestSheet" }; //create test workbook var workbook = await _synchronizer.GenerateWorkbookAsync( args, CreateTestData()); diff --git a/SharpExcel.Tests/Shared/TestModel.cs b/SharpExcel.Tests/Shared/TestModel.cs index 1672807..887b2fc 100644 --- a/SharpExcel.Tests/Shared/TestModel.cs +++ b/SharpExcel.Tests/Shared/TestModel.cs @@ -4,15 +4,15 @@ namespace SharpExcel.Tests.Shared; public class TestModel { - [SharpExcelColumnDefinition(columnName: "ID", width: 45)] + [ExcelColumnDefinition(columnName: "ID", width: 45)] public int Id { get; set; } - [SharpExcelColumnDefinition(columnName: "First Name", width: 30)] + [ExcelColumnDefinition(columnName: "First Name", width: 30)] public string FirstName { get; set; } = null!; - [SharpExcelColumnDefinition(columnName: "Last Name", width: 50)] + [ExcelColumnDefinition(columnName: "Last Name", width: 50)] public string LastName { get; set; } = null!; - [SharpExcelColumnDefinition(columnName: "Test value", width: 50)] + [ExcelColumnDefinition(columnName: "Test value", width: 50)] public TestEnum TestValue { get; set; } = TestEnum.ValueA; } \ No newline at end of file diff --git a/SharpExcel/Abstraction/ISharpExcelSynchronizer.cs b/SharpExcel/Abstraction/ISharpExcelSynchronizer.cs index 9905c6e..50dadef 100644 --- a/SharpExcel/Abstraction/ISharpExcelSynchronizer.cs +++ b/SharpExcel/Abstraction/ISharpExcelSynchronizer.cs @@ -17,7 +17,7 @@ public interface ISharpExcelSynchronizer /// Collection of arguments /// The data to generate the workbook from /// - public Task GenerateWorkbookAsync(SharpExcelArguments arguments, IEnumerable data); + public Task GenerateWorkbookAsync(ExcelArguments arguments, IEnumerable data); /// /// Reads a workbook to convert it into the given model @@ -26,7 +26,7 @@ public interface ISharpExcelSynchronizer /// /// /// - public Task> ReadWorkbookAsync(SharpExcelArguments arguments, XLWorkbook workbook); + public Task> ReadWorkbookAsync(ExcelArguments arguments, XLWorkbook workbook); /// /// Reads, then returns the supplied workbook, but highlights cells containing invalid data, using standard System.ComponentModel.DataAnnotations validation on the model @@ -34,5 +34,5 @@ public interface ISharpExcelSynchronizer /// Collection of arguments /// The workbook /// The highlighted workbook - public Task ValidateAndAnnotateWorkbookAsync(SharpExcelArguments arguments, XLWorkbook workbook); + public Task ValidateAndAnnotateWorkbookAsync(ExcelArguments arguments, XLWorkbook workbook); } \ No newline at end of file diff --git a/SharpExcel/Exporters/BaseSharpExcelSynchronizer.cs b/SharpExcel/Exporters/BaseSharpExcelSynchronizer.cs index a5b0f9d..b2823d8 100644 --- a/SharpExcel/Exporters/BaseSharpExcelSynchronizer.cs +++ b/SharpExcel/Exporters/BaseSharpExcelSynchronizer.cs @@ -23,7 +23,7 @@ public BaseSharpExcelSynchronizer(IOptions> options) _options = options; } /// - public async Task ValidateAndAnnotateWorkbookAsync(SharpExcelArguments arguments, XLWorkbook workbook) + public async Task ValidateAndAnnotateWorkbookAsync(ExcelArguments arguments, XLWorkbook workbook) { var parsedWorkbook = await ReadWorkbookAsync(arguments, workbook); ExporterHelpers.ApplyCellValidation(arguments.SheetName!, workbook, parsedWorkbook); @@ -32,7 +32,7 @@ public async Task ValidateAndAnnotateWorkbookAsync(SharpExcelArgumen /// - public virtual async Task GenerateWorkbookAsync(SharpExcelArguments arguments, IEnumerable data) + public virtual async Task GenerateWorkbookAsync(ExcelArguments arguments, IEnumerable data) { var workbook = new XLWorkbook(); @@ -63,7 +63,7 @@ public virtual async Task GenerateWorkbookAsync(SharpExcelArguments } /// - public Task> ReadWorkbookAsync(SharpExcelArguments arguments, XLWorkbook workbook) + public Task> ReadWorkbookAsync(ExcelArguments arguments, XLWorkbook workbook) { var instanceData = CreateReadInstanceData(arguments, workbook); @@ -208,7 +208,7 @@ private static int FindAndMapHeaderRow( /// arguments to use /// workbook to use /// - private SharpExcelWriterInstanceData CreateWriteInstanceData(SharpExcelArguments arguments, XLWorkbook workbook) + private SharpExcelWriterInstanceData CreateWriteInstanceData(ExcelArguments arguments, XLWorkbook workbook) { var random = new Random(); var randomNumber = random.Next(0, 1000000); @@ -234,7 +234,7 @@ private SharpExcelWriterInstanceData CreateWriteInstanceData(SharpExcelA /// arguments to use /// workbook to use /// - private SharpExcelWriterInstanceData CreateReadInstanceData(SharpExcelArguments arguments, XLWorkbook workbook) + private SharpExcelWriterInstanceData CreateReadInstanceData(ExcelArguments arguments, XLWorkbook workbook) { return new SharpExcelWriterInstanceData() { diff --git a/SharpExcel/Exporters/TypeMapper.cs b/SharpExcel/Exporters/TypeMapper.cs index 90a511a..8059e9b 100644 --- a/SharpExcel/Exporters/TypeMapper.cs +++ b/SharpExcel/Exporters/TypeMapper.cs @@ -25,7 +25,7 @@ public static PropertyDataCollection GetModelMetaData() var property = dataType.GetProperties()[columnIndex]; - var attribute = property.GetCustomAttribute(); + var attribute = property.GetCustomAttribute(); if (attribute is null) { diff --git a/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs b/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs index 487e173..334ef61 100644 --- a/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs +++ b/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs @@ -40,20 +40,11 @@ internal static void ApplyStyle(this IXLStyle excelStyle, SharpExcelCellStyle ce excelStyle.Font.FontSize = (double)cellStyle.FontSize; } - if (cellStyle.TextStyle != TextStyle.None) + if (cellStyle.TextStyle > 0) { - switch (cellStyle.TextStyle) - { - case TextStyle.Bold: - excelStyle.Font.Bold = true; - break; - case TextStyle.Italic: - excelStyle.Font.Italic = true; - break; - case TextStyle.Underlined: - excelStyle.Font.SetUnderline(XLFontUnderlineValues.Single); - break; - } + excelStyle.Font.Bold = cellStyle.TextStyle.HasFlag(TextStyle.Bold); + excelStyle.Font.Italic = cellStyle.TextStyle.HasFlag(TextStyle.Italic); + excelStyle.Font.Underline = cellStyle.TextStyle.HasFlag(TextStyle.Underlined) ? XLFontUnderlineValues.Single : XLFontUnderlineValues.None; } if (cellStyle.Borders is not null) From fc5c6588dce8907317f3f7b97e3489cc04d50e98 Mon Sep 17 00:00:00 2001 From: hurles Date: Wed, 22 Jan 2025 22:52:03 +0100 Subject: [PATCH 2/4] add more unit tests --- SharpExcel.TestApplication/Program.cs | 6 --- .../{ExcelImport.cs => ExcelImportTests.cs} | 38 ++++++++++++------- SharpExcel.Tests/SharpExcel.Tests.csproj | 8 +--- 3 files changed, 26 insertions(+), 26 deletions(-) rename SharpExcel.Tests/{ExcelImport.cs => ExcelImportTests.cs} (56%) diff --git a/SharpExcel.TestApplication/Program.cs b/SharpExcel.TestApplication/Program.cs index fac9ecc..0eb9338 100644 --- a/SharpExcel.TestApplication/Program.cs +++ b/SharpExcel.TestApplication/Program.cs @@ -45,7 +45,6 @@ async Task RunApp(IServiceProvider services) var validationExportPath = $"./OutputFolder/ErrorChecked-{Guid.NewGuid()}.xlsx"; var exportService = services.GetRequiredService>(); - #region write-workbook var excelArguments = new ExcelArguments() { SheetName = "Budgets", @@ -54,16 +53,11 @@ async Task RunApp(IServiceProvider services) using var workbook = await exportService.GenerateWorkbookAsync(excelArguments, TestDataProvider.GetTestData()); workbook.SaveAs(exportPath); - #endregion - #region validate-workbook using var errorCheckedWorkbook = await exportService.ValidateAndAnnotateWorkbookAsync(excelArguments, workbook); errorCheckedWorkbook.SaveAs(validationExportPath); - #endregion - #region read-workbook var importedWorkbook = await exportService.ReadWorkbookAsync(excelArguments, workbook); - #endregion #region write_output foreach (var dataItem in importedWorkbook.Records) diff --git a/SharpExcel.Tests/ExcelImport.cs b/SharpExcel.Tests/ExcelImportTests.cs similarity index 56% rename from SharpExcel.Tests/ExcelImport.cs rename to SharpExcel.Tests/ExcelImportTests.cs index e31fa89..d52ab9b 100644 --- a/SharpExcel.Tests/ExcelImport.cs +++ b/SharpExcel.Tests/ExcelImportTests.cs @@ -1,17 +1,18 @@ +using ClosedXML.Excel; using Microsoft.Extensions.Options; using SharpExcel.Tests.Shared; using SharpExcel.Models.Arguments; using SharpExcel.Models.Configuration.Constants; +using Shouldly; +using Xunit; namespace SharpExcel.Tests; -public class Tests +public class ExcelImportTests { private TestSynchronizer _synchronizer = null!; - - [SetUp] - public void Setup() + public ExcelImportTests() { var options = Options.Create(ExporterOptionsConstants.GetDefaultOptions()); @@ -19,14 +20,25 @@ public void Setup() } - [Test] + [Fact] public async Task CreateWorkbookTest() { var workbook = await _synchronizer.GenerateWorkbookAsync(new ExcelArguments(){ SheetName = "TestSheet"}, CreateTestData()); - Assert.That(workbook.Worksheets.FirstOrDefault(x => x.Name == "TestSheet") is not null); + workbook.Worksheets.FirstOrDefault(x => x.Name == "TestSheet").ShouldNotBeNull(); + + workbook.ShouldNotBeNull(); + //there should be 2 worksheets, a visible one for the data, and a hidden one to pull data from for the enum dropdowns + workbook.Worksheets.Count.ShouldBe(2); + + //main data worksheet + workbook.Worksheet(1).Name.ShouldBe("TestSheet"); + workbook.Worksheet(1).Visibility.ShouldBe(XLWorksheetVisibility.Visible); + + //hidden worksheet for enum dropdowns + workbook.Worksheet(2).Visibility.ShouldBe(XLWorksheetVisibility.Hidden); } - [Test] + [Fact] public async Task ReadWorkbookTest() { var args = new ExcelArguments() { SheetName = "TestSheet" }; @@ -36,13 +48,11 @@ public async Task ReadWorkbookTest() //read workbook var output = await _synchronizer.ReadWorkbookAsync(args, workbook); - Assert.Multiple(() => - { - Assert.That(output.Records.Count, Is.EqualTo(2)); - Assert.That(output.Records[0]?.Id, Is.EqualTo(1)); - Assert.That(output.Records[0]?.FirstName, Is.EqualTo("John")); - Assert.That(output.Records[0]?.LastName, Is.EqualTo("Doe")); - }); + + output.Records.Count.ShouldBe(2); + output.Records[0].Id.ShouldBe(1); + output.Records[0].FirstName.ShouldBe("John"); + output.Records[0].LastName.ShouldBe("Doe"); } private static List CreateTestData() diff --git a/SharpExcel.Tests/SharpExcel.Tests.csproj b/SharpExcel.Tests/SharpExcel.Tests.csproj index 8e4b319..45334ff 100644 --- a/SharpExcel.Tests/SharpExcel.Tests.csproj +++ b/SharpExcel.Tests/SharpExcel.Tests.csproj @@ -15,12 +15,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + From fa6ead99543b7048f8f5dc9517714d591cdd0c34 Mon Sep 17 00:00:00 2001 From: hurles Date: Wed, 22 Jan 2025 23:49:40 +0100 Subject: [PATCH 3/4] update documentation + refactoring --- README.md | 29 +++++++--- .../Constants/ExporterOptionsConstants.cs | 6 +-- .../Configuration/ExporterOptions.cs | 6 +-- .../Styling/Colorization/ExcelSharpColor.cs | 10 ++-- .../Colorization/ExcelSharpColorConstants.cs | 38 ++++++------- .../Constants/ExcelCellStyleConstants.cs | 17 ++++++ .../Constants/SharpExcelCellStyleConstants.cs | 17 ------ ...arpExcelCellStyle.cs => ExcelCellStyle.cs} | 54 ++++++++++--------- .../Styling/Rules/StylingRule.cs | 10 ++-- .../Styling/StylingCollection.cs | 6 +-- SharpExcel.TestApplication/Program.cs | 34 +++++++++--- SharpExcel.Tests/SharpExcel.Tests.csproj | 4 +- .../ServiceCollectionExtensions.cs | 4 +- SharpExcel/Exporters/ExporterHelpers.cs | 4 +- .../Exporters/SharpExcelWriterInstanceData.cs | 6 +-- .../ExcelSharpCellStyleExtensions.cs | 2 +- SharpExcel/SharpExcel.csproj | 2 +- 17 files changed, 142 insertions(+), 107 deletions(-) create mode 100644 SharpExcel.Models/Styling/Constants/ExcelCellStyleConstants.cs delete mode 100644 SharpExcel.Models/Styling/Constants/SharpExcelCellStyleConstants.cs rename SharpExcel.Models/Styling/{SharpExcelCellStyle.cs => ExcelCellStyle.cs} (55%) diff --git a/README.md b/README.md index ddb8150..2cc2cab 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,22 @@ # SharpExcel -SharpExcel is a .NET Standard 2.0+ library to simplify exporting, importing, and validate data provided using Microsoft Excel files (.xlsx, .xlsm). -The library is based on ClosedXml, and provides basic, but overridable formatting using a fluent API +SharpExcel is a powerful, easy-to-use .NET Standard 2.0 library designed to simplify the process of importing, exporting, styling, and validating Excel files. SharpExcel uses ClosedXml to handle reading and writing Excel files. + +### Main focus +The library is focused on mapping a collection of C# models to a corresponding Excel file. + +**ExcelSharp makes sure that every Excel file you export, can also be re-imported and converted to the same data as was used to export it. This is useful for providing a template for a user or client to provide data to load into a program.** + + +### Validation +The library uses FluentValidation to validate imported data. This will generate a list of exactly which cells are invalid, and why. +We can even output a new Excel file, where all invalid cells have a red color, or any other defined style. + +### Styling +SharpExcel also provides a fluent API to define styles. We can set default data and header styles and even override styles based on specific rules (for example: make a cell red when a number is below zero). + +### Auto Dropdowns +Enum properties in your model will be automatically mapped into dropdown lists for a user to select. --- ## Install SharpExcel @@ -19,7 +34,7 @@ There are a couple of simple steps to start using SharpExcel: ### Step 1: Define a data model -When defining a data model, we can use the ``[SharpExcelColumnDefinition]`` attribute to map Excel columns to model properties. +When defining a data model, we can use the ``[ExcelColumnDefinition]`` attribute to map Excel columns to model properties. We can also use Data annotation attributes to generate validation errors when reading Excel files. *In this example model we create a model for an employee:* @@ -27,17 +42,17 @@ We can also use Data annotation attributes to generate validation errors when re ```csharp public class EmployeeModel { - [SharpExcelColumnDefinition(columnName: "ID", width: 45)] + [ExcelColumnDefinition(columnName: "ID", width: 45)] public int Id { get; set; } - [SharpExcelColumnDefinition(columnName: "First Name", width: 30)] + [ExcelColumnDefinition(columnName: "First Name", width: 30)] public string FirstName { get; set; } = null!; [StringLength(12)] - [SharpExcelColumnDefinition(columnName: "Last Name", width: 50)] + [ExcelColumnDefinition(columnName: "Last Name", width: 50)] public string LastName { get; set; } = null!; - [SharpExcelColumnDefinition(columnName: "Budget", width: 15)] + [ExcelColumnDefinition(columnName: "Budget", width: 15)] public decimal Budget { get; set; } //SharpExcel also supports enum values (these will be displayed as dropdowns in Excel) diff --git a/SharpExcel.Models/Configuration/Constants/ExporterOptionsConstants.cs b/SharpExcel.Models/Configuration/Constants/ExporterOptionsConstants.cs index 3c5fb4c..5c7b121 100644 --- a/SharpExcel.Models/Configuration/Constants/ExporterOptionsConstants.cs +++ b/SharpExcel.Models/Configuration/Constants/ExporterOptionsConstants.cs @@ -16,8 +16,8 @@ public static ExporterOptions GetDefaultOptions() where TExportModel : class, new() { return new ExporterOptions() - .WithDataStyle(SharpExcelCellStyleConstants.DefaultDataStyle) - .WithHeaderStyle(SharpExcelCellStyleConstants.DefaultHeaderStyle) - .WithErrorStyle(SharpExcelCellStyleConstants.DefaultErrorStyle); + .WithDataStyle(ExcelCellStyleConstants.DefaultDataStyle) + .WithHeaderStyle(ExcelCellStyleConstants.DefaultHeaderStyle) + .WithErrorStyle(ExcelCellStyleConstants.DefaultErrorStyle); } } \ No newline at end of file diff --git a/SharpExcel.Models/Configuration/ExporterOptions.cs b/SharpExcel.Models/Configuration/ExporterOptions.cs index ba8ccbe..ca1e5e7 100644 --- a/SharpExcel.Models/Configuration/ExporterOptions.cs +++ b/SharpExcel.Models/Configuration/ExporterOptions.cs @@ -20,7 +20,7 @@ public class ExporterOptions /// /// style to use /// - public ExporterOptions WithHeaderStyle(SharpExcelCellStyle style) + public ExporterOptions WithHeaderStyle(ExcelCellStyle style) { Styling.DefaultHeaderStyle = style; return this; @@ -31,7 +31,7 @@ public ExporterOptions WithHeaderStyle(SharpExcelCellStyle style) /// /// style to use /// - public ExporterOptions WithDataStyle(SharpExcelCellStyle style) + public ExporterOptions WithDataStyle(ExcelCellStyle style) { Styling.DefaultDataStyle = style; return this; @@ -42,7 +42,7 @@ public ExporterOptions WithDataStyle(SharpExcelCellStyle style) /// /// style to use /// - public ExporterOptions WithErrorStyle(SharpExcelCellStyle style) + public ExporterOptions WithErrorStyle(ExcelCellStyle style) { Styling.DefaultErrorStyle = style; return this; diff --git a/SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs b/SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs index 9cba427..ea5fdb3 100644 --- a/SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs +++ b/SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs @@ -1,7 +1,7 @@ namespace SharpExcel.Models.Styling.Colorization; -public readonly struct SharpExcelColor : IEquatable +public readonly struct ExcelColor : IEquatable { - public SharpExcelColor(byte r, byte g, byte b, byte a = 255) + public ExcelColor(byte r, byte g, byte b, byte a = 255) { R = r; G = g; @@ -35,12 +35,12 @@ public byte A set => _colorBytes[3] = value; } - public SharpExcelColor WithAlpha(byte alpha) + public ExcelColor WithAlpha(byte alpha) { - return new SharpExcelColor(_colorBytes[0], _colorBytes[1], _colorBytes[2], alpha); + return new ExcelColor(_colorBytes[0], _colorBytes[1], _colorBytes[2], alpha); } - public bool Equals(SharpExcelColor other) + public bool Equals(ExcelColor other) { return _colorBytes.SequenceEqual(other._colorBytes); } diff --git a/SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs b/SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs index 7d2550f..877d49c 100644 --- a/SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs +++ b/SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs @@ -3,28 +3,28 @@ namespace SharpExcel.Models.Styling.Colorization; /// /// Constant values for a set of colors /// -public static class SharpExcelColorConstants +public static class ExcelColorConstants { - public static SharpExcelColor White = new(255, 255, 255); - public static SharpExcelColor Black = new(0, 0, 0); - public static SharpExcelColor Red = new(255, 0, 0); - public static SharpExcelColor Lime = new(0, 255, 0); - public static SharpExcelColor Blue = new(0, 0, 255); - public static SharpExcelColor Yellow = new(255, 255, 0); - public static SharpExcelColor Cyan = new(0, 255, 255); - public static SharpExcelColor Magenta = new(255, 0, 255); - public static SharpExcelColor Silver = new(192, 192, 192); - public static SharpExcelColor Gray = new(128, 128, 128); - public static SharpExcelColor Maroon = new(128, 0, 0); - public static SharpExcelColor Olive = new(128, 128, 0); - public static SharpExcelColor Green = new(0, 128, 0); - public static SharpExcelColor Purple = new(128, 0, 128); - public static SharpExcelColor Teal = new(0, 128, 128); - public static SharpExcelColor Navy = new(0, 0, 128); + public static ExcelColor White = new(255, 255, 255); + public static ExcelColor Black = new(0, 0, 0); + public static ExcelColor Red = new(255, 0, 0); + public static ExcelColor Lime = new(0, 255, 0); + public static ExcelColor Blue = new(0, 0, 255); + public static ExcelColor Yellow = new(255, 255, 0); + public static ExcelColor Cyan = new(0, 255, 255); + public static ExcelColor Magenta = new(255, 0, 255); + public static ExcelColor Silver = new(192, 192, 192); + public static ExcelColor Gray = new(128, 128, 128); + public static ExcelColor Maroon = new(128, 0, 0); + public static ExcelColor Olive = new(128, 128, 0); + public static ExcelColor Green = new(0, 128, 0); + public static ExcelColor Purple = new(128, 0, 128); + public static ExcelColor Teal = new(0, 128, 128); + public static ExcelColor Navy = new(0, 0, 128); //transparent - public static SharpExcelColor Transparent = new(0, 0, 0, 0); - public static SharpExcelColor TransparentWhite = new(255, 255, 255, 0); + public static ExcelColor Transparent = new(0, 0, 0, 0); + public static ExcelColor TransparentWhite = new(255, 255, 255, 0); } diff --git a/SharpExcel.Models/Styling/Constants/ExcelCellStyleConstants.cs b/SharpExcel.Models/Styling/Constants/ExcelCellStyleConstants.cs new file mode 100644 index 0000000..e26d94a --- /dev/null +++ b/SharpExcel.Models/Styling/Constants/ExcelCellStyleConstants.cs @@ -0,0 +1,17 @@ +using SharpExcel.Models.Styling.Borders; +using SharpExcel.Models.Styling.Colorization; +using SharpExcel.Models.Styling.Text; + +namespace SharpExcel.Models.Styling.Constants; + +public static class ExcelCellStyleConstants +{ + public static ExcelCellStyle DefaultHeaderStyle = + new(ExcelColorConstants.Black, ExcelColorConstants.Transparent, TextStyle.Bold, borders: BorderCollection.HeaderDefault); + + public static ExcelCellStyle DefaultDataStyle = + new(ExcelColorConstants.Black, ExcelColorConstants.Transparent, TextStyle.None, borders: BorderCollection.DataDefault); + + public static ExcelCellStyle DefaultErrorStyle = + new(new (80, 40, 40), new (255, 150, 150), TextStyle.None, borders: BorderCollection.DataDefault); +} \ No newline at end of file diff --git a/SharpExcel.Models/Styling/Constants/SharpExcelCellStyleConstants.cs b/SharpExcel.Models/Styling/Constants/SharpExcelCellStyleConstants.cs deleted file mode 100644 index a345908..0000000 --- a/SharpExcel.Models/Styling/Constants/SharpExcelCellStyleConstants.cs +++ /dev/null @@ -1,17 +0,0 @@ -using SharpExcel.Models.Styling.Borders; -using SharpExcel.Models.Styling.Colorization; -using SharpExcel.Models.Styling.Text; - -namespace SharpExcel.Models.Styling.Constants; - -public static class SharpExcelCellStyleConstants -{ - public static SharpExcelCellStyle DefaultHeaderStyle = - new(SharpExcelColorConstants.Black, SharpExcelColorConstants.Transparent, TextStyle.Bold, borders: BorderCollection.HeaderDefault); - - public static SharpExcelCellStyle DefaultDataStyle = - new(SharpExcelColorConstants.Black, SharpExcelColorConstants.Transparent, TextStyle.None, borders: BorderCollection.DataDefault); - - public static SharpExcelCellStyle DefaultErrorStyle = - new(new (80, 40, 40), new (255, 150, 150), TextStyle.None, borders: BorderCollection.DataDefault); -} \ No newline at end of file diff --git a/SharpExcel.Models/Styling/SharpExcelCellStyle.cs b/SharpExcel.Models/Styling/ExcelCellStyle.cs similarity index 55% rename from SharpExcel.Models/Styling/SharpExcelCellStyle.cs rename to SharpExcel.Models/Styling/ExcelCellStyle.cs index 2ab7b9c..974f6e5 100644 --- a/SharpExcel.Models/Styling/SharpExcelCellStyle.cs +++ b/SharpExcel.Models/Styling/ExcelCellStyle.cs @@ -7,9 +7,11 @@ namespace SharpExcel.Models.Styling; /// /// Struct defining the styling of a cell /// -public struct SharpExcelCellStyle +public record struct ExcelCellStyle { - public SharpExcelCellStyle(SharpExcelColor textColor, SharpExcelColor backgroundColor, TextStyle textStyle, double? rowHeight = null, double? fontSize = null, + public ExcelCellStyle() { } + + public ExcelCellStyle(ExcelColor textColor, ExcelColor backgroundColor, TextStyle textStyle, double? rowHeight = null, double? fontSize = null, BorderCollection? borders = null) { Borders = borders ?? BorderCollection.DataDefault; @@ -24,13 +26,13 @@ public SharpExcelCellStyle(SharpExcelColor textColor, SharpExcelColor background /// Color used for text within a cell /// if null, default color is used /// - public SharpExcelColor? TextColor { get; set; } = SharpExcelColorConstants.Black; + public ExcelColor? TextColor { get; set; } = ExcelColorConstants.Black; /// /// Background color used for cell /// if null, default color is used /// - public SharpExcelColor? BackgroundColor { get; set;} = SharpExcelColorConstants.TransparentWhite; + public ExcelColor? BackgroundColor { get; set;} = ExcelColorConstants.TransparentWhite; /// /// Text style (Bold, Italic, etc) @@ -55,11 +57,11 @@ public SharpExcelCellStyle(SharpExcelColor textColor, SharpExcelColor background /// public BorderCollection? Borders { get; set; } = BorderCollection.DataDefault; - public SharpExcelCellStyle WithTextColor(SharpExcelColor color) + public ExcelCellStyle WithTextColor(ExcelColor color) { - return new SharpExcelCellStyle( + return new ExcelCellStyle( color, - BackgroundColor ?? SharpExcelColorConstants.TransparentWhite, + BackgroundColor ?? ExcelColorConstants.TransparentWhite, TextStyle, RowHeight, FontSize, @@ -67,10 +69,10 @@ public SharpExcelCellStyle WithTextColor(SharpExcelColor color) ); } - public SharpExcelCellStyle WithBackgroundColor(SharpExcelColor color) + public ExcelCellStyle WithBackgroundColor(ExcelColor color) { - return new SharpExcelCellStyle( - TextColor ?? SharpExcelColorConstants.Black, + return new ExcelCellStyle( + TextColor ?? ExcelColorConstants.Black, color, TextStyle, RowHeight, @@ -79,11 +81,11 @@ public SharpExcelCellStyle WithBackgroundColor(SharpExcelColor color) ); } - public SharpExcelCellStyle WithTextStyle(TextStyle textStyle) + public ExcelCellStyle WithTextStyle(TextStyle textStyle) { - return new SharpExcelCellStyle( - TextColor ?? SharpExcelColorConstants.Black, - BackgroundColor ?? SharpExcelColorConstants.TransparentWhite, + return new ExcelCellStyle( + TextColor ?? ExcelColorConstants.Black, + BackgroundColor ?? ExcelColorConstants.TransparentWhite, textStyle, RowHeight, FontSize, @@ -91,11 +93,11 @@ public SharpExcelCellStyle WithTextStyle(TextStyle textStyle) ); } - public SharpExcelCellStyle WithRowHeight(double height) + public ExcelCellStyle WithRowHeight(double height) { - return new SharpExcelCellStyle( - TextColor ?? SharpExcelColorConstants.Black, - BackgroundColor ?? SharpExcelColorConstants.TransparentWhite, + return new ExcelCellStyle( + TextColor ?? ExcelColorConstants.Black, + BackgroundColor ?? ExcelColorConstants.TransparentWhite, TextStyle, height, FontSize, @@ -103,11 +105,11 @@ public SharpExcelCellStyle WithRowHeight(double height) ); } - public SharpExcelCellStyle WithFontSize(double fontSize) + public ExcelCellStyle WithFontSize(double fontSize) { - return new SharpExcelCellStyle( - TextColor ?? SharpExcelColorConstants.Black, - BackgroundColor ?? SharpExcelColorConstants.TransparentWhite, + return new ExcelCellStyle( + TextColor ?? ExcelColorConstants.Black, + BackgroundColor ?? ExcelColorConstants.TransparentWhite, TextStyle, RowHeight, fontSize, @@ -115,11 +117,11 @@ public SharpExcelCellStyle WithFontSize(double fontSize) ); } - public SharpExcelCellStyle WithBorders(BorderCollection borders) + public ExcelCellStyle WithBorders(BorderCollection borders) { - return new SharpExcelCellStyle( - TextColor ?? SharpExcelColorConstants.Black, - BackgroundColor ?? SharpExcelColorConstants.TransparentWhite, + return new ExcelCellStyle( + TextColor ?? ExcelColorConstants.Black, + BackgroundColor ?? ExcelColorConstants.TransparentWhite, TextStyle, RowHeight, FontSize, diff --git a/SharpExcel.Models/Styling/Rules/StylingRule.cs b/SharpExcel.Models/Styling/Rules/StylingRule.cs index 42665a7..8f13170 100644 --- a/SharpExcel.Models/Styling/Rules/StylingRule.cs +++ b/SharpExcel.Models/Styling/Rules/StylingRule.cs @@ -6,9 +6,9 @@ public class StylingRule private List> Conditions { get; set; } = new(); - private SharpExcelCellStyle? StyleWhenTrue { get; set; } = new(); + private ExcelCellStyle? StyleWhenTrue { get; set; } = new(); - private SharpExcelCellStyle? StyleWhenFalse { get; set; } = new(); + private ExcelCellStyle? StyleWhenFalse { get; set; } = new(); public StylingRule WithCondition(Func condition) @@ -25,7 +25,7 @@ public StylingRule ForProperty(string propertyName) return this; } - public SharpExcelCellStyle? EvaluateRules(TModel model) + public ExcelCellStyle? EvaluateRules(TModel model) { bool allAreTrue = false; foreach (var condition in Conditions) @@ -39,14 +39,14 @@ public StylingRule ForProperty(string propertyName) return allAreTrue ? StyleWhenTrue : StyleWhenFalse; } - public StylingRule WhenTrue(SharpExcelCellStyle style) + public StylingRule WhenTrue(ExcelCellStyle style) { StyleWhenTrue = style; //return this object so we can chain calls return this; } - public StylingRule WhenFalse(SharpExcelCellStyle style) + public StylingRule WhenFalse(ExcelCellStyle style) { StyleWhenFalse = style; //return this object so we can chain calls diff --git a/SharpExcel.Models/Styling/StylingCollection.cs b/SharpExcel.Models/Styling/StylingCollection.cs index a1aef0f..575d252 100644 --- a/SharpExcel.Models/Styling/StylingCollection.cs +++ b/SharpExcel.Models/Styling/StylingCollection.cs @@ -5,12 +5,12 @@ namespace SharpExcel.Models.Styling; public class StylingCollection { - public SharpExcelCellStyle DefaultHeaderStyle { get; set; } = SharpExcelCellStyleConstants.DefaultHeaderStyle; + public ExcelCellStyle DefaultHeaderStyle { get; set; } = ExcelCellStyleConstants.DefaultHeaderStyle; - public SharpExcelCellStyle DefaultDataStyle { get; set; } = SharpExcelCellStyleConstants.DefaultDataStyle; + public ExcelCellStyle DefaultDataStyle { get; set; } = ExcelCellStyleConstants.DefaultDataStyle; - public SharpExcelCellStyle DefaultErrorStyle { get; set; } = SharpExcelCellStyleConstants.DefaultErrorStyle; + public ExcelCellStyle DefaultErrorStyle { get; set; } = ExcelCellStyleConstants.DefaultErrorStyle; public List> Rules { get; set; } = new(); } \ No newline at end of file diff --git a/SharpExcel.TestApplication/Program.cs b/SharpExcel.TestApplication/Program.cs index 0eb9338..8bacc53 100644 --- a/SharpExcel.TestApplication/Program.cs +++ b/SharpExcel.TestApplication/Program.cs @@ -14,24 +14,39 @@ HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(null); -builder.Services.AddSynchronizer(options => +//Here we add a synchronizer to the service collection +builder.Services.AddSharpExcelSynchronizer(options => { - options.WithDataStyle(SharpExcelCellStyleConstants.DefaultDataStyle); - options.WithHeaderStyle(new SharpExcelCellStyle() + //set default style of + options.WithDataStyle(ExcelCellStyleConstants.DefaultDataStyle); + options.WithHeaderStyle(new ExcelCellStyle() .WithTextStyle(TextStyle.Bold | TextStyle.Underlined) .WithFontSize(18.0)); + //here we define the style of an errored cell. + //This is only applicable when we want to return a validated excel file. + //Any cells that have validation errors will have this style options.WithErrorStyle( - SharpExcelCellStyleConstants.DefaultDataStyle - .WithTextColor(new SharpExcelColor(255, 100, 100)) - .WithBackgroundColor(new SharpExcelColor(255, 100, 100, 70)) + ExcelCellStyleConstants.DefaultDataStyle + .WithTextColor(new ExcelColor(255, 100, 100)) + .WithBackgroundColor(new ExcelColor(255, 100, 100, 70)) ); + + //We can also define rules for styling options.WithStylingRule(rule => { + //define which property we want to check rule.ForProperty(nameof(TestExportModel.Budget)); + + //define the condition for this rule rule.WithCondition(x => x.Budget < 0); - rule.WhenTrue(SharpExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(255, 100, 100))); - rule.WhenFalse(SharpExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(80, 160, 80))); + + //define style to do when the rule is true + rule.WhenTrue(ExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(255, 100, 100))); + + //define style for when the rule is false + //can be omitted to use default style + rule.WhenFalse(ExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(80, 160, 80))); }); }); @@ -39,6 +54,7 @@ await RunApp(host.Services); await host.RunAsync(); +//this is our test application async Task RunApp(IServiceProvider services) { var exportPath = $"./OutputFolder/TestExport-{Guid.NewGuid()}.xlsx"; @@ -82,4 +98,6 @@ void WriteOutputRow(TestExportModel testExportModel, ExcelReadResult - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/SharpExcel/DependencyInjection/ServiceCollectionExtensions.cs b/SharpExcel/DependencyInjection/ServiceCollectionExtensions.cs index 538fdb0..654e866 100644 --- a/SharpExcel/DependencyInjection/ServiceCollectionExtensions.cs +++ b/SharpExcel/DependencyInjection/ServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ public static class SharpExcelServiceCollectionExtensions /// the ServiceCollection /// the options to configure this SharpExcel exporter with. Default options are used when null /// - public static void AddSynchronizer(this IServiceCollection services, Action>? options) + public static void AddSharpExcelSynchronizer(this IServiceCollection services, Action>? options) where TExportModel : class, new() { services.Configure(options ?? (_ => ExporterOptionsConstants.GetDefaultOptions())); @@ -31,7 +31,7 @@ public static void AddSynchronizer(this IServiceCollection service /// the options to configure this SharpExcel exporter with. Default options are used when null /// The type of the exporter. Must be inherited from BaseExcelExporter /// any class to use as data model - public static void AddSynchronizer(this IServiceCollection services, Action>? options) + public static void AddSharpExcelSynchronizer(this IServiceCollection services, Action>? options) where TExportModel : class, new() where TExporter : BaseSharpExcelSynchronizer { diff --git a/SharpExcel/Exporters/ExporterHelpers.cs b/SharpExcel/Exporters/ExporterHelpers.cs index 3f18e08..d241b03 100644 --- a/SharpExcel/Exporters/ExporterHelpers.cs +++ b/SharpExcel/Exporters/ExporterHelpers.cs @@ -32,7 +32,7 @@ public static void ApplyCellValidation(string sheetName, XLWorkbook work { stringBuilder.AppendLine(item.ErrorMessage); } - cell.Style.ApplyStyle(SharpExcelCellStyleConstants.DefaultErrorStyle); + cell.Style.ApplyStyle(ExcelCellStyleConstants.DefaultErrorStyle); cell.CreateComment().AddText(stringBuilder.ToString()); } } @@ -173,7 +173,7 @@ private static void WriteDataCell( /// row to apply row height to if necessary /// type of the data item being processed /// - private static SharpExcelCellStyle GetCellStyle(SharpExcelWriterInstanceData instance, TModel dataItem, PropertyData mapping, IXLRow row) + private static ExcelCellStyle GetCellStyle(SharpExcelWriterInstanceData instance, TModel dataItem, PropertyData mapping, IXLRow row) where TModel : class { var dataStyle = instance.DataStyle; diff --git a/SharpExcel/Exporters/SharpExcelWriterInstanceData.cs b/SharpExcel/Exporters/SharpExcelWriterInstanceData.cs index cfd41c8..4bafa75 100644 --- a/SharpExcel/Exporters/SharpExcelWriterInstanceData.cs +++ b/SharpExcel/Exporters/SharpExcelWriterInstanceData.cs @@ -16,17 +16,17 @@ internal class SharpExcelWriterInstanceData /// /// Header style to use for this instance /// - public SharpExcelCellStyle HeaderStyle { get; set; } + public ExcelCellStyle HeaderStyle { get; set; } /// /// Error style to use for this instance /// - public SharpExcelCellStyle ErrorStyle { get; set; } + public ExcelCellStyle ErrorStyle { get; set; } /// /// Style to use for data cells /// - public SharpExcelCellStyle DataStyle { get; set; } + public ExcelCellStyle DataStyle { get; set; } /// /// lookup for styling rules, so we can look up rules for properties faster diff --git a/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs b/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs index 334ef61..952bd3c 100644 --- a/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs +++ b/SharpExcel/Extensions/ExcelSharpCellStyleExtensions.cs @@ -15,7 +15,7 @@ internal static class SharpExcelCellStyleExtensions /// /// /// - internal static void ApplyStyle(this IXLStyle excelStyle, SharpExcelCellStyle cellStyle) + internal static void ApplyStyle(this IXLStyle excelStyle, ExcelCellStyle cellStyle) { if (cellStyle.BackgroundColor.HasValue) { diff --git a/SharpExcel/SharpExcel.csproj b/SharpExcel/SharpExcel.csproj index fb7d279..6442fe9 100644 --- a/SharpExcel/SharpExcel.csproj +++ b/SharpExcel/SharpExcel.csproj @@ -15,7 +15,7 @@ - + From 5c33d2b47e3127ed93f131f23e791be723bbbffc Mon Sep 17 00:00:00 2001 From: hurles Date: Thu, 23 Jan 2025 00:29:43 +0100 Subject: [PATCH 4/4] update docs + renamed some files --- README.md | 63 ++++++++++++++----- .../{ExcelSharpColor.cs => ExcelColor.cs} | 0 ...lorConstants.cs => ExcelColorConstants.cs} | 0 .../Extensions/StylingRuleExtensions.cs | 6 -- .../Styling/StylingCollection.cs | 1 - 5 files changed, 49 insertions(+), 21 deletions(-) rename SharpExcel.Models/Styling/Colorization/{ExcelSharpColor.cs => ExcelColor.cs} (100%) rename SharpExcel.Models/Styling/Colorization/{ExcelSharpColorConstants.cs => ExcelColorConstants.cs} (100%) delete mode 100644 SharpExcel.Models/Styling/Extensions/StylingRuleExtensions.cs diff --git a/README.md b/README.md index 2cc2cab..510123b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ SharpExcel is a powerful, easy-to-use .NET Standard 2.0 library designed to simp ### Main focus The library is focused on mapping a collection of C# models to a corresponding Excel file. -**ExcelSharp makes sure that every Excel file you export, can also be re-imported and converted to the same data as was used to export it. This is useful for providing a template for a user or client to provide data to load into a program.** +**SharpExcel makes sure that every Excel file you export, can also be re-imported and converted to the same data as was used to export it. This is useful for providing a template for a user or client to provide data to load into a program.** ### Validation @@ -68,17 +68,17 @@ public class EmployeeModel In the simplest case we can register a synchronizer for the given model to the service collection. This is a default implementation and can be used for simple imports/exports. ```csharp -builder.Services.AddSynchronizer() +builder.Services.AddSharpExcelSynchronizer() ``` Optionally, we can configure the synchronizer further: ```csharp -builder.Services.AddSynchronizer(options => +builder.Services.AddSharpExcelSynchronizer(options => { //apply default styling - options.WithDataStyle(SharpExcelCellStyleConstants.DefaultDataStyle); + options.WithDataStyle(ExcelCellStyleConstants.DefaultDataStyle); //in this case we customize the styling for the header - options.WithHeaderStyle(new SharpExcelCellStyle() + options.WithHeaderStyle(new ExcelCellStyle() .WithTextStyle(TextStyle.Bold) .WithFontSize(18.0)); }); @@ -87,18 +87,18 @@ If we want to switch styling conditionally, styling rules can be added in the fo *In this example, we want the text in the cell to be red when the budget is < 0* ```csharp -builder.Services.AddSynchronizer(options => +builder.Services.AddSharpExcelSynchronizer(options => { options.WithStylingRule(rule => { //select property of model by name - rule.ForProperty(nameof(TestExportModel.Budget)); + rule.ForProperty(nameof(EmployeeModel.Budget)); //provide a condition rule.WithCondition(x => x.Budget < 0); //color text red when condition is true - rule.WhenTrue(SharpExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(255, 100, 100))); + rule.WhenTrue(ExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(255, 100, 100))); //color text green when condition is false - rule.WhenFalse(SharpExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(80, 160, 80))); + rule.WhenFalse(ExcelCellStyleConstants.DefaultDataStyle.WithTextColor(new(80, 160, 80))); }); }); ``` @@ -125,7 +125,7 @@ public class ApplicationService *The following example shows how to write a collection of ``EmployeeModel`` to an excel file:* ```csharp - var arguments = new SharpExcelArguments() + var arguments = new ExcelArguments() { //sheet to read from SheetName = "Employees", @@ -158,7 +158,7 @@ The excel file must have a header row with the column names defined in the model // in this case we load from a file, but this can also be a stream using var workbook = new XLWorkbook("C:/Documents/filename.xslx"); - var arguments = new SharpExcelArguments() + var arguments = new ExcelArguments() { //which sheet to read data from SheetName = "Employees", @@ -168,11 +168,46 @@ The excel file must have a header row with the column names defined in the model await _synchronizer.ReadWorkbookAsync(arguments, workbook); ``` -The loading of the excel file (and the XLWorkbook type) are provided by ClosedXml -For more information and documentation on these types visit [ClosedXml](https://github.com/ClosedXML/ClosedXML) -#### Validating Excel files +The loading of the Excel file (and the XLWorkbook type) are provided by ClosedXml +For more information and documentation on these types visit [ClosedXml](https://github.com/ClosedXML/ClosedXML) +The ``ReadWorkbookAsync`` method, returns the following model, where ``TModel`` is the model used for this SharpExcel Synchronizer: ```csharp +public class ExcelReadResult + where TModel : class +{ + //The data that has been read + public List Records { get; set; } = new(); + //Contains list of validation results, grouped by record + //these will contain the address of the cell, and the reason why validation has failed + public Dictionary ValidationResults { get; set; } = new(); +} ``` + +#### Returning a validated Excel file + +We can also return the provided workbook, but with a different style applied to cells that are invalid. +SharpExcel will also generate annotations for these cells to show the user why they are not valid. + +```csharp + using var errorCheckedWorkbook = await _synchronizer.ValidateAndAnnotateWorkbookAsync(excelArguments, workbook); + errorCheckedWorkbook.SaveAs(validationExportPath); +``` + +We can customize the Styling of these invalid cells during the initial setup of our SharpExcel Synchronizer. + +```csharp +builder.Services.AddSharpExcelSynchronizer(options => +{ + //here we define the style of an errored cell. + //This is only applicable when we want to return a validated excel file. + //Any cells that have validation errors will have this style + options.WithErrorStyle( + ExcelCellStyleConstants.DefaultDataStyle + .WithTextColor(new ExcelColor(255, 100, 100)) + .WithBackgroundColor(new ExcelColor(255, 100, 100, 70)) + ); +}); +``` \ No newline at end of file diff --git a/SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs b/SharpExcel.Models/Styling/Colorization/ExcelColor.cs similarity index 100% rename from SharpExcel.Models/Styling/Colorization/ExcelSharpColor.cs rename to SharpExcel.Models/Styling/Colorization/ExcelColor.cs diff --git a/SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs b/SharpExcel.Models/Styling/Colorization/ExcelColorConstants.cs similarity index 100% rename from SharpExcel.Models/Styling/Colorization/ExcelSharpColorConstants.cs rename to SharpExcel.Models/Styling/Colorization/ExcelColorConstants.cs diff --git a/SharpExcel.Models/Styling/Extensions/StylingRuleExtensions.cs b/SharpExcel.Models/Styling/Extensions/StylingRuleExtensions.cs deleted file mode 100644 index 6ec334c..0000000 --- a/SharpExcel.Models/Styling/Extensions/StylingRuleExtensions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SharpExcel.Models.Styling.Extensions; - -public static class StylingRuleExtensions -{ - -} \ No newline at end of file diff --git a/SharpExcel.Models/Styling/StylingCollection.cs b/SharpExcel.Models/Styling/StylingCollection.cs index 575d252..13be4de 100644 --- a/SharpExcel.Models/Styling/StylingCollection.cs +++ b/SharpExcel.Models/Styling/StylingCollection.cs @@ -9,7 +9,6 @@ public class StylingCollection public ExcelCellStyle DefaultDataStyle { get; set; } = ExcelCellStyleConstants.DefaultDataStyle; - public ExcelCellStyle DefaultErrorStyle { get; set; } = ExcelCellStyleConstants.DefaultErrorStyle; public List> Rules { get; set; } = new();