Skip to content

開始使用 Excely

Max Zheng edited this page Jan 18, 2024 · 30 revisions

安裝

若您僅使用 CSV 相關功能,請執行以下指令以下載 Excely 本體:

dotnet add package Excely

若您想要使用 Excel 相關功能,請根據您偏好的依賴套件選擇對應的版本:

EPPlus

dotnet add package Excely.LGPL.EPPlus

ClosedXML

dotnet add package Excely.ClosedXML

開始使用

以下以 EPPlus.LGPL 依賴版本,進行 Excel 匯入、匯出的示範。

匯出

以下的範例展示了如何從 List 匯出為 Excel:

首先是本次做為示範類別的 Student 類別,其定義如下:

class Student
{
    public int Id { get; set; }

    public string Name { get; set; } = null!;

    public DateTime? Birthday { get; set; }

    public Student(int id, string name, DateTime? birthday)
    {
        Id = id;
        Name = name;
        Birthday = birthday;
    }

    public Student() { }
}

接下來的範例中,我們的目標就是將 List<Student> 匯出為 Excel 在匯入回來。 我們接著看下去:

// 創建物件列表
var students = new List<Student>()
{
    new Student(id: 0, name: "Test1", birthday: DateTime.Now),
    new Student(id: 1, name: "Test2", birthday: DateTime.Now),
};

// 建立匯出 List<Student> 的 exporter
var exporter = ExcelyExporter.FromClassList<Student>();

// 匯出為 Excel
using var excel = exporter.ToExcel(students);

可以看到我們首先呼叫靜態類別 ExcelyExporter 中的 FromClassList<T> 方法, 來創造一個可以輸入 List<T> 的 exporter。

ExcelyExporter 可以幫助您創建各種輸入版本的 exporter, 例如 FromDictionaryList 可以創建接受字典輸入的 exporter。

FromClassList<T> 有兩個參數可以輸入:

  • options - 此參數讓您可以自定義匯出流程的邏輯,詳細的使用方式請參考(尚未編寫)。
  • shaders - 此參數讓您在匯出後,能使用 shader 來依序調整匯出結果。關於 shader 的用法,請參考美化匯出結果

ToExcel 則可以輸入以下參數:

  • sourceData - 匯入資料來源。
  • worksheetName - 匯出時創建的工作表名稱。
  • startCell - 開始匯出的座標(不填入則為最右上角)。

ToExcel 實際上是 ToWorksheet 的包裝,若您已經有想匯出的目標 excel 實例,請考慮改用 ToWorksheet

匯入

以下的範例展示了如何從 worksheet 匯入為 List:

// 接續匯出章節匯出的檔案
var worksheet = excel.Workbook.Worksheets.First();

// 建立接受 worksheet 的 importer
var importer = new XlsxImporter();

// 匯入為 IEnumerable<Student>
var importResult = importer.ToClassList<Student>(worksheet);

與匯出時不同,這裡我們不是呼叫靜態類別來產生 importer,而是直接建立一個特定的 importer 物件, 這是因為匯入來源通常都是由套件依賴版本(如本例中的 Excely.EPPlus.LGPL)提供。

此處的 new XlsxImporter() 建構子可以輸入兩種參數:

  • startCell - 代表開始讀取來源的座標。若不填則從 worksheet 的最左上角開始讀取。
  • endCell - 代表強制結束讀取的座標,只會讀取 startCell 到 endCell 間的內容。若不填則不設限。

ToClassList 則可以輸入來源資料及自定義的轉換邏輯(可選)。

關於 options 參數的詳細使用方式請參考自訂轉換邏輯

自訂轉換邏輯

自訂匯出邏輯

接續上面的例子,若我們想使 Student.Birthday 以字串形式(yyyy-MM-dd)匯出, 則需要使用 FromClassList<T>option 參數, options 參數接受一個 ClassListTableFactoryOptions<T> 型別的物件,

以下是 ClassListTableFactoryOptions<T> 可以設定的幾個 Property:

  • WithSchema: 決定匯出時是否帶有表頭。
  • PropertyShowPolicy: 決定 Property 是否應作為欄位匯出。
  • PropertyNamePolicy: 決定 Property 作為欄位時的名稱。
  • PropertyOrderPolicy: 決定 Property 作為欄位時的順序。
  • CustomValuePolicy: 決定資料寫入欄位時的值。

此處我們先展示以 CustomValuePolicy 來使 Student.Birthday 以字串形式(yyyy-MM-dd)匯出的寫法:

// 延續前一章節的匯出範例...

// 建立自訂轉換邏輯
var exportOptions = new ClassListTableFactoryOptions<Student>
{
    CustomValuePolicy = (property, obj) => property.Name switch
    {
        nameof(Student.Birthday) => obj.Birthday?.ToString("yyyy-MM-dd"),
        _ => ClassListTableFactoryOptions<Student>.DefaultCustomValuePolicy(property, obj)
    }
};

// 建立匯出 List<Student> 的 exporter
var exporter = ExcelyExporter.FromClassList<Student>(options: exportOptions);

// 匯出為 Excel
using var excel = exporter.ToExcel(students);

CustomValuePolicy 是一個由 ClassListTableFactoryOptions 定義好的委派, 其第一個參數代表當前正在處理的 Property, 第二個參數為當前正在處理的來源物件(要匯出的物件)。 在上面的範例中,我們設定了將資料寫入至 Excel 欄位時的轉換邏輯, 當處理 Student.Birthday 欄位時,將寫入的值改為 yyyy-MM-dd 形式的字串, 其餘欄位則呼叫 ClassListTableFactoryOptions<Student> 定義的 DefaultCustomValuePolicy(property, obj), 以預設處理方式來處理。

ClassListTableFactoryOptions<Student>.DefaultCustomValuePolicy(property, obj) 其實就是 property.GetValue(obj), 若您很清楚知道預設行為,也可以採取此種方式,使程式碼更為直觀。 更多預設行為的資訊,請參考(尚未編寫)。

ClassListTableFactoryOptions 的其他自定義參數使用方式請參考(尚未編寫)。

自訂匯入邏輯

接續上一章節,若我們想將帶有匯出為 yyyy-MM-dd 形式的 Excel 匯入回 IEnumerable, 則需要使用 ToClassList<T>options 參數, 其接受一個 ClassListTableConverterOptions<T> 型別的物件。

以下是 ClassListTableConverterOptions<T> 可以設定的幾個 Property:

  • WithSchema: 匯入的 Table 是否含有表頭。
  • ThrowWhenError: 當轉換發生錯誤時是否立刻擲出異常。
  • EnableAutoTypeConversion: 當寫入的值與目標型別不同時,是否自動嘗試轉換。
  • PropertyNamePolicy: 當 WithSchematrue 時,決定 Property 作為欄位時的名稱。
  • PropertyIndexPolicy: 當 WithSchemafalse 時,取得 Property 出現在表頭時的位置。
  • PropertyValueSettingPolicy: 決定將值寫入至 Property 時應寫入的值。
  • ErrorHandlingPolicy: 將值輸入進物件發生錯誤時,決定錯誤處理方式。

為了使 yyyy-MM-dd 形式的字串轉換回 DateTime 形式, 我們需要設定 PropertyValueSettingPolicy 如下:

// 延續前一章節的匯入範例...

// 建立自訂轉換邏輯
var importOptions = new ClassListTableConverterOptions<Student>
{
    PropertyValueSettingPolicy = (property, originalValue) => property.Name switch
    {
        nameof(Student.Birthday) => originalValue != null ? DateTime.Parse(originalValue.ToString()) : null,
        _ => ClassListTableConverterOptions<Student>.DefaultPropertyValueSettingPolicy(property, originalValue)
    }
};

// 建立接受 worksheet 的 importer
var importer = new XlsxImporter();

// 匯入為 IEnumerable<Student>
var importResult = importer.ToClassList<Student>(worksheet, options: importOptions);

PropertyValueSettingPolicy 是一個由 ClassListTableConverterOptions 定義好的委派, 其第一個參數代表當前正在處理的 Property, 第二個參數為從資料來源讀取到的值。 在上面的範例中,我們設定了讀取 Excel 內容時的轉換邏輯, 當處理 Student.Birthday 欄位時,將讀取到的 yyyy-MM-dd 形式字串轉換為 DateTime,其餘欄位則呼叫預設處理方式。

ClassListTableConverterOptions<Student>.DefaultPropertyValueSettingPolicy(property, originalValue) 其實就是回傳 originalValue, 若您很清楚知道預設行為,也可以採取此種方式,使程式碼更為直觀。 更多預設行為的資訊,請參考(尚未編寫)。

順帶再介紹 ClassListTableConverterOptions 另一個參數 EnableAutoTypeConversion, 當此參數為 true 時,會自動嘗試將來源值轉型為目標型別, 其轉換方式是先嘗試使用 TypeConverter,若該型別沒有對應的 TypeConverter, 或是 TypeConverter 轉換失敗時,則嘗試使用強制轉型。 有了這個方便的參數,其實不需要大費周章的自行撰寫 format string 到 DateTime 的轉換。

自動轉型的過程效率較低,當需要轉型的欄位較多或追求效能表現時,請考慮停用自動轉型,並自己撰寫對應邏輯。

ClassListTableConverterOptions 的其他自定義參數使用方式請參考(尚未編寫)。

美化匯出結果

目前為止,我們匯出的 Excel 都沒有做任何外觀上的調整。 為了增強使用者體驗,你可能會想為匯出資料加上主題色彩、表頭篩選或自適應欄位寬度等等, 這時你可以使用 Shader 功能來輕鬆完成設定。

根據不同的匯出目標(如Excel、CSV)以及不同的版本依賴,可能會有不同的可用 Shader, 這裡我們以美化 Excel 來舉例。

EPPlus.LGPL 依賴版本中目前有以下 Shader 可供選擇:

  • CellFittingShader: 欄位大小自適應
  • SchemaFilterShader: 啟用表頭篩選
  • TableThemeShader: 表格色彩美化
  • ErrorMarkShader: 在指定欄位標註備註,並使其文字色彩為紅色

更多支援的 Shader 請參考(尚未編寫)

所有 Shader 的基本使用方式都相同,只需要建立實例,並呼叫 Excute 函式:

// 延續匯出範例...
using var excel = exporter.ToExcel(students);
var worksheet = excel.Workbook.Worksheets.First();

// 建立 Shader
var cellFittingShader = new CellFittingShader();
// 執行 Shader
cellFittingShader.Excute(worksheet);

除了這種使用方式,也可以使用 FromClassList<T> 的 shaders 參數, 一次傳入一整組 Shader,並在匯出後自動執行:

// 以匯出範例做修改...

// 建立匯出 List<Student> 的 exporter
var exporter = ExcelyExporter.FromClassList<Student>(
    options: exportOptions,
    shaders: new IShader[]
    {
        new CellFittingShader(),
        new SchemaFilterShader(),
    });
Clone this wiki locally