From 811890cbfc662c8126b3325dd100ef6ff3ce3a8a Mon Sep 17 00:00:00 2001 From: Max Zheng <34936931+maxzh1999tw@users.noreply.github.com> Date: Sun, 10 Dec 2023 10:55:01 +0800 Subject: [PATCH] =?UTF-8?q?ClosedXML=20=E4=BE=9D=E8=B3=B4=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E8=A3=9C=E4=B8=8A=20TableThemeShader=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=8C=AF=E8=AA=A4=E8=99=95=E7=90=86=E7=AF=84?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Excely.ClosedXML/Shaders/ErrorMarkShader.cs | 1 - Excely.ClosedXML/Shaders/TableThemeShader.cs | 100 ++++++++++++++++++ .../Exemples/SimpleClassListToXlsxExemple.cs | 2 +- .../XlsxImportErrorHandlingExemple.cs | 99 +++++++++++++++++ Excely.Example.Console/Program.cs | 2 +- 5 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 Excely.ClosedXML/Shaders/TableThemeShader.cs create mode 100644 Excely.Example.Console/Exemples/XlsxImportErrorHandlingExemple.cs diff --git a/Excely.ClosedXML/Shaders/ErrorMarkShader.cs b/Excely.ClosedXML/Shaders/ErrorMarkShader.cs index 044c46b..1832d31 100644 --- a/Excely.ClosedXML/Shaders/ErrorMarkShader.cs +++ b/Excely.ClosedXML/Shaders/ErrorMarkShader.cs @@ -18,7 +18,6 @@ public class ErrorMarkShader : XlsxShaderBase public XLColor TextColor { get; set; } = XLColor.Red; /// 匯入錯誤資料 - /// Comment 作者(不得為空) public ErrorMarkShader(Dictionary errorCells) { CellErrors = errorCells; diff --git a/Excely.ClosedXML/Shaders/TableThemeShader.cs b/Excely.ClosedXML/Shaders/TableThemeShader.cs new file mode 100644 index 0000000..4edcec9 --- /dev/null +++ b/Excely.ClosedXML/Shaders/TableThemeShader.cs @@ -0,0 +1,100 @@ +using ClosedXML.Excel; +using System.Drawing; + +namespace Excely.ClosedXML.Shaders +{ + /// + /// 將一段範圍內的儲存格視為表格,並為其套上表格造型。 + /// + public class TableThemeShader : XlsxShaderBase + { + /// + /// 表格左上角的儲存格座標。 + /// + public CellLocation StartCell { get; set; } = new(0, 0); + + /// + /// 表頭高度。 + /// + public int SchemaHeight { get; set; } = 1; + + /// + /// 表格寬度。 + /// + public int TableWidth { get; set; } + + /// + /// 表格高度。 + /// + public int TableHeight { get; set; } + + /// + /// 表格主題。 + /// + public TableTheme Theme { get; set; } = TableTheme.Default; + + public TableThemeShader() { } + + /// 表格寬度(0為自適應) + /// 表格高度(0為自適應) + public TableThemeShader(int tableWidth, int tableHeight) + { + TableWidth = tableWidth; + TableHeight = tableHeight; + } + + protected override void ExcuteOnWorksheet(IXLWorksheet worksheet) + { + var tableWidth = TableWidth; + if(TableWidth == 0) + { + tableWidth = worksheet.LastColumnUsed().ColumnNumber(); + } + + var tableHeight = TableHeight; + if (TableHeight == 0) + { + tableHeight = worksheet.LastRowUsed().RowNumber(); + } + + // 設定標題的背景色和文字色 + var header = worksheet.Range(StartCell.Row + 1, StartCell.Column + 1, StartCell.Row + SchemaHeight, StartCell.Column + tableWidth); + header.Style.Fill.BackgroundColor = XLColor.FromColor(Theme.HeaderBackgroundColor); + header.Style.Font.FontColor = XLColor.FromColor(Theme.HeaderTextColor); + header.Style.Font.Bold = true; + + // 給整個表格設定邊框色 + var table = worksheet.Range(StartCell.Row + 1, StartCell.Column + 1, StartCell.Row + tableHeight, StartCell.Column + tableWidth); + table.Style.Border.OutsideBorder = table.Style.Border.InsideBorder = XLBorderStyleValues.Thin; + table.Style.Border.OutsideBorderColor = table.Style.Border.InsideBorderColor = XLColor.FromColor(Theme.BorderColor); + } + } + + /// + /// 用於表達表格主題的結構。 + /// + public struct TableTheme + { + /// + /// 表頭背景色。 + /// + public Color HeaderBackgroundColor { get; set; } + + /// + /// 表頭文字顏色。 + /// + public Color HeaderTextColor { get; set; } + + /// + /// 邊框顏色。 + /// + public Color BorderColor { get; set; } + + public static TableTheme Default => new() + { + HeaderBackgroundColor = Color.FromArgb(68, 114, 196), + HeaderTextColor = Color.White, + BorderColor = Color.FromArgb(68, 114, 196), + }; + } +} \ No newline at end of file diff --git a/Excely.Example.Console/Exemples/SimpleClassListToXlsxExemple.cs b/Excely.Example.Console/Exemples/SimpleClassListToXlsxExemple.cs index 7a4639f..2252224 100644 --- a/Excely.Example.Console/Exemples/SimpleClassListToXlsxExemple.cs +++ b/Excely.Example.Console/Exemples/SimpleClassListToXlsxExemple.cs @@ -47,7 +47,7 @@ public static void Demo() PropertyValueSettingPolicy = (p, value) => p.Name switch { nameof(SimpleClass.DateTimeField) => value != null ? DateTime.Parse(value.ToString()) : null, - nameof(SimpleClass.BoolField) => value != null ? value == "是" : null, + nameof(SimpleClass.BoolField) => value != null ? value?.ToString() == "是" : null, _ => value }, }; diff --git a/Excely.Example.Console/Exemples/XlsxImportErrorHandlingExemple.cs b/Excely.Example.Console/Exemples/XlsxImportErrorHandlingExemple.cs new file mode 100644 index 0000000..b0564d4 --- /dev/null +++ b/Excely.Example.Console/Exemples/XlsxImportErrorHandlingExemple.cs @@ -0,0 +1,99 @@ +using ClosedXML.Excel; +using Excely.ClosedXML.Shaders; +using Excely.ClosedXML.Workflows; +using Excely.Example.Console.Models; +using Excely.Example.Console.Utilities; +using Excely.Shaders; +using Excely.TableConverters; +using Excely.TableFactories; +using Excely.Workflows; + +namespace Excely.Example.Console.Exemples +{ + internal class XlsxImportErrorHandlingExemple + { + private static IEnumerable GetList() + { + return new List() + { + new SimpleClass() + { + Id = 1, + StringField = "比較長的文字欄位111111111111111111", + DateTimeField = DateTime.Now, + BoolField = true, + }, + new SimpleClass() + { + Id = 2, + StringField = "比較長的文字欄位222222222222222222", + DateTimeField = DateTime.Now, + BoolField = false, + }, + }; + } + + private static XLWorkbook GetExampleWorkbook() + { + var list = GetList(); + var exportOption = new ClassListTableFactoryOptions + { + PropertyNamePolicy = p => p.GetDisplayName(), + CustomValuePolicy = (p, obj) => p.Name switch + { + // 故意設定錯誤的日期格式 + nameof(SimpleClass.DateTimeField) => obj.DateTimeField?.ToString("yyyy/yyyy/dd"), + nameof(SimpleClass.BoolField) => obj.BoolField == null ? null : (obj.BoolField.Value ? "是" : "否"), + _ => p.GetValue(obj) + }, + }; + + var shaders = new IShader[] + { + new SchemaFilterShader(), + new CellFittingShader(), + }; + + var exporter = ExcelyExporter.FromClassList(exportOption, shaders); + return exporter.ToExcel(list); + } + + public static void Demo() + { + using var excel = GetExampleWorkbook(); + var worksheet = excel.Worksheets.First(); + var importer = new XlsxImporter(); + var errorDict = new Dictionary(); + + var importOption = new ClassListTableConverterOptions + { + PropertyNamePolicy = p => p.GetDisplayName(), + PropertyValueSettingPolicy = (p, value) => p.Name switch + { + nameof(SimpleClass.BoolField) => value != null ? value?.ToString() == "是" : null, + _ => value + }, + ErrorHandlingPolicy = (cellLocation, obj, p, value, ex) => + { + switch (p.Name) + { + case nameof(SimpleClass.DateTimeField): + errorDict.Add(cellLocation, "錯誤的日期格式"); + break; + default: + errorDict.Add(cellLocation, ex.Message); + break; + }; + return true; + } + }; + + var importedList = importer.ToClassList(worksheet, importOption); + new ErrorMarkShader(errorDict).Excute(worksheet); + new CellFittingShader().Excute(worksheet); + new SchemaFilterShader().Excute(worksheet); + new TableThemeShader().Excute(worksheet); + excel.SaveAs("XlsxImportErrorHandlingExemple.xlsx"); + } + } +} diff --git a/Excely.Example.Console/Program.cs b/Excely.Example.Console/Program.cs index 21fab20..120f034 100644 --- a/Excely.Example.Console/Program.cs +++ b/Excely.Example.Console/Program.cs @@ -1,3 +1,3 @@ using Excely.Example.Console.Exemples; -SimpleClassListToXlsxExemple.Demo(); \ No newline at end of file +XlsxImportErrorHandlingExemple.Demo(); \ No newline at end of file