ExcelPatternTool 開箱即用的Excel工具包現已釋出!

林曉lx發表於2023-10-25


應用系統開發中少不了跟Excel打交道,基於NPOI開發了ExcelPatternTool,與目前主流框架對比ExcelPatternTool著重單元格樣式的控制,對於初始資料匯入、報表匯出等簡單的Excel功能提升易用性。

ExcelPatternTool

開箱即用的Excel工具包。
Excel資料校驗,資料匯入,以及自定義樣式填充資料匯出到Excel文件。

功能

可設定列屬性,包括樣式,公式,註解;
可配置規則獨立設定單元格樣式;
可配置規則對Excel校驗,包括數值校驗和公式校驗,內建Lambda表示式和正規表示式兩個預設的校驗器;
可擴充套件的介面封裝和元件。

特點:

提供獨立Excel校驗工具;
提供Cli版本和帶UI(WPF)版本的程式;
提供ODBC擴充套件;
基於json檔案或型別+成員屬性(Attribute)的配置方式。

快速開始

在專案中引用ExcelPatternTool.Core

dotnet add package ExcelPatternTool.Core

從Excel匯入

Importer import = new Importer();
import.LoadXlsx(File.ReadAllBytes(filePath));   //匯入xlsx檔案
// or
import.LoadXls(File.ReadAllBytes(filePath));    //或匯入xls檔案
var importOption = new ImportOption<T>(0, 0);
var result = import.Process<T>(importOption).ToList()

Console.WriteLine(result);      //匯入完成!

匯出Excel

IList<T> src = ...  //準備資料


Exporter exporter = new Exporter();
exporter.DumpXlsx(filePath);    //匯出xlsx檔案
// or
exporter.DumpXls(filePath);     //或匯出xls檔案
var exportOption = new ExportOption<T>(0);
var issuccess = exporter.Process(src, exportOption); //匯出完成!

使用說明

編輯你的C#類,此類將作為ExcelPatternTool匯入匯出功能的承載實體型別,繼承自IExcelEntity

常規型別

常規型別是C#基本資料型別,直接輸出的為單元格值

可定義 stringDateTimeintdoublebool

高階型別

使用高階型別匯入時不光讀取資料,還將讀取單元格細節,匯出至Excel時,將保留這些細節。

高階型別是繼承自IAdvancedType的類,往往是一個泛型,它的型別引數為常規型別,對應實際的單元格值。

高階型別有:"包含註解","包含樣式","包含公式","全包含"型別。

  1. ICommentedType: 包含單元格註解;
  2. IStyledType: 包含單元格樣式;
  3. IFormulatedType: 包含單元格公式的物件;
  4. IFullAdvancedType: 包含了單元格註解,樣式,公式。

Importable註解

  1. Order 列序號為此列在Excel中的編號,從0開始,即A列對應0,B列對應1 ...

  2. Ignore 為True時將忽略這一列,等效於ExcelEntity無此屬性

Exportable註解

  1. Order 列序號為此列在Excel中的編號,從0開始,即A列對應0,B列對應1 ...

  2. Name 列名稱,將指定匯出時的該列第一行名稱

  3. Ignore 為True時將忽略這一列,等效於ExcelEntity無此屬性

  4. Format 指定單元格格式,格式約定請參考Excel 自定義單元格格式

  5. Type: 單元格型別, Exportable中可指定Type型別的為

    含義
    Any 自定義
    Text 文字
    Numeric 數值
    Date 時間
    Bool 布林值

    若不指定則根據屬性型別自動判斷

IImportOption匯入選項

  1. EntityType 指定一個實體型別,將使用此型別中的屬性作為匯入列
  2. SheetName 指定匯入的Sheet名稱,若不指定將匯入第SheetNumber個Sheet
  3. SheetNumber 指定匯入的Sheet編號,從0開始。
  4. SkipRows 指定跳過的行數,從0開始。

IExportOption匯出選項

  1. EntityType 指定一個實體型別,將使用此型別中的屬性作為匯出列
  2. SheetName 指定匯出的Sheet名稱,預設Sheet1
  3. SkipRows 指定跳過的行數,從0開始。
  4. GenHeaderRow 指定是否生成表頭行,預設為False
  5. StyleMapperProvider 指定樣式對映器型別

單元格樣式

樣式支援文字顏色、背景顏色、邊框顏色、字型、字號、加粗、下劃線、斜體、刪除線等。
填充規則支援全域性樣式,列樣式,以及根據樣式對映器的規則填充單元格獨立樣式。

單元格透過StyleMetadata樣式後設資料定義樣式,樣式後設資料包括:

  1. FontColor 字型顏色
  2. FontName 字型名稱
  3. FontSize 字型大小(單位px)
  4. BorderColor 邊框顏色
  5. BackColor 背景顏色
  6. IsItalic 是否斜體
  7. IsBold 是否加粗
  8. IsStrikeout 是否刪除線
  9. FontUnderlineType 下劃線型別
  10. FontSuperScript 上標下標

StyleMapping樣式對映

樣式對映器用於將實體型別屬性對映為單元格樣式,可自定義實現,也可使用內建的樣式對映器。

  1. Target 指定樣式對映的目標屬性,可選Value單元格值或Formula單元格公式
  2. Convention 指定規則,預設的規則有LambdaExpressionRegularExpression,分別對應Lambda表示式和正規表示式
  3. Expression 指定表示式內容
  4. MappingConfig 指定表示式結果對應的樣式後設資料

自定義樣式:
透過繼承StyleMapperProvider類,重寫GetStyleMappingContainers方法,返回的字典稱之為樣式對映容器,作用是將規則對應的數值與樣式一一對應。

下面例子說明當“體溫”列中的資料超過36.5時,將字型顏色設定為紅色,否則為黑色。

public override Dictionary<string, StyleMapping> GetStyleMappingContainers()
{
    return new Dictionary<string, StyleMapping>
    {
        "體溫",
        new StyleMapping()
        {
            Target = Target.Value,
            Convention = "LambdaExpression",
            Expression = "{value}>36.5",
            MappingConfig = new Dictionary<object, StyleMetadata>
            {
                { true, new StyleMetadata(){  FontColor="Red"} } ,
                { false, new StyleMetadata(){  FontColor="Black"} }
            }
        }
    }
    
}

建立後將匯出選項的StyleMapperProvider指定為該樣式對映器型別

使用資料庫作為資料來源

  1. 若涉及資料庫匯入匯出,請使用Table標籤指定表名稱, 使用Key標籤指定主鍵型別,無鍵實體型別請使用Keyless
    詳情請參考EFCore官方文件https://docs.microsoft.com/zh-cn/ef/core/modeling/

示例

Sample1:不同型別欄位匯出

假設某類中有如下欄位

public class WriteRowTestEntity : IExcelEntity
{
    [Exportable(ignore: true)]
    public long RowNumber { get; set; }

    [Exportable("日期", Order = 1, Format = "yyyy\"年\"m\"月\"d\"日\";@")]
    public DateTime DateTimeValue { get; set; }

    [Exportable("整數", Order = 2)]
    public int IntValue { get; set; }

    [Exportable("小數", Order = 3)]
    public double DoubleValue { get; set; }

    [Exportable("布林值", Order = 4)]
    public bool BoolValue { get; set; }

    [Exportable("公式", Order = 7)]
    public FormulatedType<int> IntWithFormula { get; set; }
}

匯出時日期按照給定格式生成,整數、小數、布林值根據型別自動判斷,公式將匯出公式內容。

在這裡插入圖片描述

Sample2:高階型別匯入和匯出

假設某類中有如下欄位

    public class AdvancedTypeTestEntity : IExcelEntity
    {

        [Exportable(ignore: true)]
        [Importable(ignore: true)]
        public long RowNumber { get; set; }

        [Exportable("全", Order = 4)]
        [Importable(0)]
        public FullAdvancedType<string> StringWithFullValue { get; set; }
    }

StringWithFullValue將在匯入時儲存單元格的註解,樣式,公式,以及值。匯出時按照原樣匯出。

在這裡插入圖片描述

Sample3:員工健康體檢

假設某類中有如下欄位

    public class EmployeeHealthEntity : IExcelEntity
    {


        [Exportable(Ignore = true)]
        public long RowNumber { get; set; }

        [Importable(0)]
        [Exportable("姓名")]
        public string ClientName { get; set; }

        [Importable(1)]
        [Exportable("收縮壓")]
        public string BloodPressure2 { get; set; }

        [Importable(2)]
        [Exportable("舒張壓")]
        public string BloodPressure1 { get; set; }

        [Importable(3)]
        [Exportable("體溫")]
        public string Temperature { get; set; }

    }

自定義樣式對映器EmployeeHealthEntityStyleMapperProvider類,重寫獲取樣式容器GetStyleMappingContainers方法,

內容如下:

public class EmployeeHealthEntityStyleMapperProvider : StyleMapperProvider
{
    public override Dictionary<string, StyleMapping> GetStyleMappingContainers()
    {
        var result = new Dictionary<string, StyleMapping>
        {
            {
                "體溫",
                new StyleMapping()
                {
                    Target = Target.Value,
                    Convention = "LambdaExpression",
                    Expression = "{value}>=36.5",
                    MappingConfig = new Dictionary<object, StyleMetadata>
                    {
                        { true, new StyleMetadata(){  FontColor="Red"} } ,
                        { false, new StyleMetadata(){  FontColor="Black"} }
                    }
                }
            },
                {
                "收縮壓",
                new StyleMapping()
                {
                    Target = Target.Value,
                    Convention = "BloodPressureResultExpression",
                    MappingConfig = new Dictionary<object, StyleMetadata>
                    {
                        { "偏低異常", new StyleMetadata(){  FontColor="Orange"} } ,
                        { "偏高異常", new StyleMetadata(){  FontColor="Red"} },
                        { "正常", new StyleMetadata(){  FontColor="Black"} }
                    }
                }

            },
                {
                "舒張壓",
                new StyleMapping()
                {
                    Target = Target.Value,
                    Convention = "BloodPressureResultExpression",
                    MappingConfig = new Dictionary<object, StyleMetadata>
                    {
                        { "偏低異常", new StyleMetadata(){  FontColor="Orange"} } ,
                        { "偏高異常", new StyleMetadata(){  FontColor="Red"} },
                        { "正常", new StyleMetadata(){  FontColor="Black"} }
                    }
                }

            },


        };
        return result;
    }

重寫InitConventions將血壓的樣式對映規則定義為BloodPressureResultExpression,並新增到基類的樣式對映規則中,內容如下:

    public override Dictionary<string, StyleConvention> InitConventions()
    {

        var baseOne = base.InitConventions();
        baseOne.Add("BloodPressureResultExpression", new StyleConvention(new Func<string, StyleMapping, object, StyleMetadata>((key, c, e) =>
        {
            StyleMetadata result = null;
            var lambdaParser = new LambdaParser();
            if (c == null)
            {
                return null;
            }
            var val = double.Parse((string)TryGetValue(key, e));
            if (key == nameof(EmployeeHealthEntity.BloodPressure2))
            {
                if (val > 140)
                {
                    result = c.MappingConfig["偏高異常"];

                }
                else if (val < 90)
                {
                    result = c.MappingConfig["偏低異常"];

                }
                else
                {
                    result = c.MappingConfig["正常"];
                }
            }

            else if (key == nameof(EmployeeHealthEntity.BloodPressure1))
            {
                if (val > 90)
                {
                    result = c.MappingConfig["偏高異常"];

                }
                else if (val < 60)
                {
                    result = c.MappingConfig["偏低異常"];

                }
                else
                {
                    result = c.MappingConfig["正常"];
                }
            }



            return result;

        })));
        return baseOne;

    }
}

在這裡插入圖片描述

工具

Roslyn Syntax Tool

  • 此工具能將C#程式碼,轉換成使用語法工廠構造器(SyntaxFactory)生成等效語法樹程式碼

已知問題

作者資訊

作者:林小

郵箱:jevonsflash@qq.com

License

The MIT License (MIT)

專案地址

Github:ExcelPatternTool

相關文章