├── .gitignore ├── pics ├── pic1.PNG ├── pic2.PNG ├── pic3.PNG ├── pic4.PNG ├── pic5.PNG ├── pic6.PNG ├── pic7.PNG └── pic6new.PNG ├── ExcelCake.Example ├── Template │ ├── 复杂格式测试模板.xlsx │ └── 复杂格式测试模板(新语法).xlsx ├── ExcelCake.Example.csproj ├── Entities │ ├── AccountInfo.cs │ ├── GradeReportInfo.cs │ ├── ClassInfo.cs │ └── UserInfo.cs └── Program.cs ├── ExcelCake.Test ├── UnitTest1.cs └── ExcelCake.Test.csproj ├── ExcelCake ├── Intrusive │ ├── ExcelBase.cs │ ├── ImportStyle.cs │ ├── Attribute │ │ ├── ExportMergeAttribute.cs │ │ ├── ExportAttribute.cs │ │ ├── ImportEntityAttribute.cs │ │ ├── ImportAttribute.cs │ │ └── ExportEntityAttribute.cs │ ├── ImportColumn.cs │ ├── ExportStyle.cs │ ├── ExportColumn.cs │ ├── ImportExcelSetting.cs │ ├── ExportExcelSetting.cs │ ├── Extension │ │ ├── ImportExtension.cs │ │ └── ExportExtension.cs │ ├── ExcelHelper.cs │ └── Enum │ │ └── EnumColor.cs ├── ExcelCake.csproj ├── ImportFormatException.cs ├── NoIntrusive │ ├── TemplateSetting │ │ ├── TemplateRange.cs │ │ ├── TemplateSettingRange.cs │ │ ├── TemplateSettingField.cs │ │ ├── TemplateSettingRangeGrid.cs │ │ ├── TemplateSettingRangeFree.cs │ │ ├── TemplateSettingSheet.cs │ │ └── TemplateSettingRangeChart.cs │ ├── TemplateSettingRange.cs │ ├── DataObject.cs │ ├── TemplateSettingSheet.cs │ └── ExcelTemplate.cs └── ExcelCommon.cs ├── ExcelCake.sln ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | packages 2 | bin 3 | obj 4 | .vs 5 | *.docx 6 | *.doc -------------------------------------------------------------------------------- /pics/pic1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic1.PNG -------------------------------------------------------------------------------- /pics/pic2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic2.PNG -------------------------------------------------------------------------------- /pics/pic3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic3.PNG -------------------------------------------------------------------------------- /pics/pic4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic4.PNG -------------------------------------------------------------------------------- /pics/pic5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic5.PNG -------------------------------------------------------------------------------- /pics/pic6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic6.PNG -------------------------------------------------------------------------------- /pics/pic7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic7.PNG -------------------------------------------------------------------------------- /pics/pic6new.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/pics/pic6new.PNG -------------------------------------------------------------------------------- /ExcelCake.Example/Template/复杂格式测试模板.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/ExcelCake.Example/Template/复杂格式测试模板.xlsx -------------------------------------------------------------------------------- /ExcelCake.Example/Template/复杂格式测试模板(新语法).xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/winstonwxj/ExcelCake/HEAD/ExcelCake.Example/Template/复杂格式测试模板(新语法).xlsx -------------------------------------------------------------------------------- /ExcelCake.Test/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace ExcelCake.Test 4 | { 5 | [TestClass] 6 | public class UnitTest1 7 | { 8 | [TestMethod] 9 | public void TestMethod1() 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ExcelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | public abstract class ExcelBase 9 | { 10 | public string ExcelName { set; get; } 11 | public string SheetName { set; get; } 12 | public int RowIndex { set; get; } 13 | public int ColumnIndex { set; get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ExcelCake/ExcelCake.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ImportStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | public class ImportStyle 9 | { 10 | /// 11 | /// 12 | /// 13 | public int TitleRowIndex { set; get; } 14 | 15 | /// 16 | /// 17 | /// 18 | public int HeadRowIndex { set; get; } 19 | 20 | /// 21 | /// 22 | /// 23 | public int DataRowIndex { set; get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ExcelCake.Example/ExcelCake.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Always 15 | 16 | 17 | Always 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ExcelCake.Test/ExcelCake.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ExcelCake.Example/Entities/AccountInfo.cs: -------------------------------------------------------------------------------- 1 | using ExcelCake.Intrusive; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.Example 8 | { 9 | [ExportEntity("账号信息")] 10 | public class AccountInfo:ExcelBase 11 | { 12 | [Export("编号", 1)] 13 | public int ID { set; get; } 14 | 15 | [Export("昵称", 2)] 16 | public string Nickname { set; get; } 17 | 18 | [Export("密码", 3)] 19 | public string Password { set; get; } 20 | 21 | [Export("旧密码", 4)] 22 | public string OldPassword { set; get; } 23 | 24 | [Export("状态", 5)] 25 | public int AccountStatus { set; get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ExcelCake/ImportFormatException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace ExcelCake 7 | { 8 | [Serializable] 9 | public class ImportFormatException: ApplicationException 10 | { 11 | private string[] _Messages; 12 | 13 | public string[] Messages 14 | { 15 | get 16 | { 17 | return _Messages; 18 | } 19 | } 20 | 21 | public ImportFormatException() 22 | { 23 | _Messages = new string[0]; 24 | } 25 | 26 | public ImportFormatException(params string[] messages) 27 | { 28 | _Messages = messages; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateRange.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace ExcelCake.NoIntrusive 9 | { 10 | [Serializable] 11 | internal abstract class TemplateSettingBase 12 | { 13 | internal string Content { set; get; } 14 | 15 | /// 16 | /// 配置所在单元格 17 | /// 18 | internal ExcelRangeBase CurrentCell { set; get; } 19 | 20 | /// 21 | /// 作用范围 22 | /// 23 | internal ExcelRangeBase ScopeRange { set; get; } 24 | 25 | protected abstract void AnalyseSetting(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSettingRange.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | internal class TemplateSettingRange 10 | { 11 | public string Type { set; get; } 12 | public string DataSource { set; get; } 13 | //public string Address { set; get; } 14 | public string AddressLeftTop { set; get; } 15 | public string AddressRightBottom { set; get; } 16 | public string Field { set; get; } 17 | public string SettingString { set; get; } 18 | public ExcelRangeBase CurrentCell { set; get; } 19 | public int FromRow { set; get; } 20 | public int FromCol { set; get; } 21 | public int ToRow { set; get; } 22 | public int ToCol { set; get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Attribute/ExportMergeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | /// 9 | /// 导出列合并特性 10 | /// 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public class ExportMergeAttribute: Attribute 13 | { 14 | private string _MergeText { get; set; } 15 | 16 | /// 17 | /// 合并后文本 18 | /// 19 | public string MergeText 20 | { 21 | get 22 | { 23 | return _MergeText; 24 | } 25 | set 26 | { 27 | _MergeText = value; 28 | } 29 | } 30 | 31 | public ExportMergeAttribute(string mergeText) 32 | { 33 | _MergeText = mergeText ?? ""; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingRange.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | [Serializable] 10 | internal abstract class TemplateSettingRange: TemplateSettingBase 11 | { 12 | internal List Fields { get; set; } 13 | 14 | internal string DataSource { set; get; } 15 | //public string Address { set; get; } 16 | internal string AddressLeftTop { set; get; } 17 | internal string AddressRightBottom { set; get; } 18 | 19 | internal int FromRow { set; get; } 20 | internal int FromCol { set; get; } 21 | internal int ToRow { set; get; } 22 | internal int ToCol { set; get; } 23 | 24 | internal abstract void Draw(ExcelWorksheet workSheet, ExcelObject dataSource); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ExcelCake.Example/Entities/GradeReportInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ExcelCake.Example 8 | { 9 | public class GradeReportInfo 10 | { 11 | public string ReportTitle { set; get; } 12 | /// 13 | /// 各班级各科目及格人数列表 14 | /// 15 | public List List1 { set; get; } 16 | /// 17 | /// 各班级各科目平均成绩 18 | /// 19 | public List List2 { set; get; } 20 | /// 21 | /// 各班级总分情况 22 | /// 23 | public List List3 { set; get; } 24 | 25 | public GradeReportInfo() 26 | { 27 | List1 = new List(); 28 | List2 = new List(); 29 | List3 = new List(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ExcelCake.Example/Entities/ClassInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ExcelCake.Example 8 | { 9 | public class ClassInfo 10 | { 11 | public string ClassName { set; get; } 12 | public int PassCountSubject1 { set; get; } 13 | public int PassCountSubject2 { set; get; } 14 | public int PassCountSubject3 { set; get; } 15 | public int PassCountSubject4 { set; get; } 16 | public int PassCountSubject5 { set; get; } 17 | 18 | public double ScoreAvgSubject1 { set; get; } 19 | public double ScoreAvgSubject2 { set; get; } 20 | public double ScoreAvgSubject3 { set; get; } 21 | public double ScoreAvgSubject4 { set; get; } 22 | public double ScoreAvgSubject5 { set; get; } 23 | 24 | public double ScoreTotalMax { set; get; } 25 | public double ScoreTotalAvg { set; get; } 26 | public double ScoreTotalPassRate { set; get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ExcelCake.Example/Entities/UserInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using ExcelCake.Intrusive; 8 | using System.Drawing; 9 | 10 | namespace ExcelCake.Example 11 | { 12 | [ExportEntity(EnumColor.LightGray, "用户信息")] 13 | [ImportEntity(titleRowIndex:1,headRowIndex:2,dataRowIndex:4)] 14 | public class UserInfo: ExcelBase 15 | { 16 | [Export(name:"编号", index:1,prefix:"ID:")] 17 | [Import(name:"编号",prefix:"ID:")] 18 | public int ID { set; get; } 19 | 20 | [Export("姓名", 2)] 21 | [Import("姓名")] 22 | public string Name { set; get; } 23 | 24 | [Export("性别", 3)] 25 | [Import("性别")] 26 | public string Sex { set; get; } 27 | 28 | [Export(name:"年龄", index:4,suffix:"岁")] 29 | [Import(name:"年龄",suffix:"岁",dataVerReg: @"^[1-9]\d*$", isRegFailThrowException:false)] 30 | public int Age { set; get; } 31 | 32 | [ExportMerge("联系方式")] 33 | [Export("电子邮件", 5)] 34 | [Import("电子邮件")] 35 | public string Email { set; get; } 36 | 37 | [ExportMerge("联系方式")] 38 | [Export("手机", 6)] 39 | [Import("手机")] 40 | public string TelPhone { set; get; } 41 | 42 | public override string ToString() 43 | { 44 | return string.Format($"ID:{ID},Name:{Name},Sex:{Sex},Age:{Age},Email:{Email},TelPhone:{TelPhone}"); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ImportColumn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace ExcelCake.Intrusive 8 | { 9 | public class ImportColumn 10 | { 11 | public string Text { set; get; } 12 | public string Name { set; get; } 13 | public int ColumnIndex { set; get; } 14 | public bool IsUseTempField { set; get; } 15 | public string TempField { set; get; } 16 | public string Prefix { set; get; } 17 | public string Suffix { set; get; } 18 | public string DataVerReg { set; get; } 19 | public bool IsRegFailThrowException { set; get; } 20 | 21 | 22 | public ImportColumn() 23 | { 24 | IsUseTempField = false; 25 | } 26 | 27 | public ImportColumn(PropertyInfo property) 28 | { 29 | if (property == null) 30 | { 31 | return; 32 | } 33 | var importAttrArry = property.GetCustomAttributes(typeof(ImportAttribute), true); 34 | if (importAttrArry != null && importAttrArry.Length > 0) 35 | { 36 | var import = ((ImportAttribute)importAttrArry[0]); 37 | Name = property.Name; 38 | Text = import.Name; 39 | IsUseTempField = import.IsUseTempField; 40 | TempField = import.TempField; 41 | Prefix = import.Prefix; 42 | Suffix = import.Suffix; 43 | DataVerReg = import.DataVerReg; 44 | IsRegFailThrowException = import.IsRegFailThrowException; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ExportStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.Intrusive 8 | { 9 | public class ExportStyle 10 | { 11 | /// 12 | /// 标题背景颜色 13 | /// 14 | public Color TitleColor { set; get; } 15 | 16 | /// 17 | /// 标题文本 18 | /// 19 | public string Title { set; get; } 20 | 21 | /// 22 | /// 标题文本字号 23 | /// 24 | public int TitleFontSize { set; get; } 25 | 26 | /// 27 | /// 标题是否粗体 28 | /// 29 | public bool IsTitleBold { set; get; } 30 | 31 | /// 32 | /// 标题合并列数 33 | /// 34 | public int TitleColumnSpan { set; get; } 35 | 36 | /// 37 | /// 列头背景颜色 38 | /// 39 | public Color HeadColor { set; get; } 40 | 41 | /// 42 | /// 列头字号 43 | /// 44 | public int HeadFontSize { set; get; } 45 | 46 | /// 47 | /// 列头是否粗体 48 | /// 49 | public bool IsHeadBold { set; get; } 50 | 51 | /// 52 | /// 内容背景色 53 | /// 54 | public Color ContentColor { set; get; } 55 | 56 | /// 57 | /// 内容字号 58 | /// 59 | public int ContentFontSize { set; get; } 60 | 61 | /// 62 | /// 内容是否粗体 63 | /// 64 | public bool IsContentBold { set; get; } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ExportColumn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace ExcelCake.Intrusive 8 | { 9 | public class ExportColumn 10 | { 11 | public string Text { set; get; } 12 | public string Value { set; get; } 13 | public int Index { set; get; } 14 | public string Prefix { set; get; } 15 | public string Suffix { set; get; } 16 | public string MergeText { set; get; } 17 | 18 | public ExportColumn() 19 | { 20 | 21 | } 22 | 23 | public ExportColumn(PropertyInfo property) 24 | { 25 | if (property == null) 26 | { 27 | return; 28 | } 29 | var exportAttrArry = property.GetCustomAttributes(typeof(ExportAttribute), true); 30 | if (exportAttrArry != null && exportAttrArry.Length > 0) 31 | { 32 | var export = ((ExportAttribute)exportAttrArry[0]); 33 | string displayName = property.Name; 34 | if (!string.IsNullOrEmpty(export.Name)) 35 | { 36 | displayName = export.Name; 37 | } 38 | Text = displayName; 39 | Value = property.Name; 40 | Index = export.SortIndex; 41 | Prefix = export.Prefix; 42 | Suffix = export.Suffix; 43 | var mergeAttrArry = property.GetCustomAttributes(typeof(ExportMergeAttribute), true); 44 | if (mergeAttrArry != null && mergeAttrArry.Length > 0) 45 | { 46 | MergeText = ((ExportMergeAttribute)mergeAttrArry[0]).MergeText; 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ImportExcelSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | public class ImportExcelSetting 9 | { 10 | public List ImportColumns { set; get; } 11 | public ImportStyle ImportStyle { set; get; } 12 | 13 | private ImportExcelSetting() 14 | { 15 | 16 | } 17 | 18 | public ImportExcelSetting(Type type) 19 | { 20 | ImportStyle = new ImportStyle(); 21 | ImportColumns = new List(); 22 | if (type == null) 23 | { 24 | return; 25 | } 26 | 27 | #region 组织表头 28 | var classAttrArry = type.GetCustomAttributes(typeof(ImportEntityAttribute), true); 29 | if (classAttrArry == null || classAttrArry.Length == 0) 30 | { 31 | return; 32 | } 33 | 34 | var importEntity = (ImportEntityAttribute)classAttrArry[0]; 35 | 36 | ImportStyle.TitleRowIndex = importEntity.TitleRowIndex; 37 | ImportStyle.HeadRowIndex = importEntity.HeadRowIndex; 38 | ImportStyle.DataRowIndex = importEntity.DataRowIndex; 39 | 40 | var properties = type.GetProperties(); 41 | 42 | foreach (var proper in properties) 43 | { 44 | var importAttrArry = proper.GetCustomAttributes(typeof(ImportAttribute), true); 45 | if (importAttrArry != null && importAttrArry.Length > 0) 46 | { 47 | var column = new ImportColumn(proper); 48 | if (column != null) 49 | { 50 | ImportColumns.Add(column); 51 | } 52 | } 53 | } 54 | #endregion 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Attribute/ExportAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | /// 9 | /// 导出特性,标注导出的属性 10 | /// 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public class ExportAttribute:Attribute 13 | { 14 | private string _Name; 15 | private int _SortIndex; 16 | private string _Prefix; 17 | private string _Suffix; 18 | 19 | /// 20 | /// 导出名称 21 | /// 22 | public string Name 23 | { 24 | get 25 | { 26 | return _Name; 27 | } 28 | } 29 | 30 | /// 31 | /// 导出排序索引 32 | /// 33 | public int SortIndex 34 | { 35 | get 36 | { 37 | return _SortIndex; 38 | } 39 | } 40 | 41 | /// 42 | /// 前缀 43 | /// 44 | public string Prefix 45 | { 46 | get 47 | { 48 | return _Prefix; 49 | } 50 | set 51 | { 52 | _Prefix = value; 53 | } 54 | } 55 | 56 | /// 57 | /// 后缀 58 | /// 59 | public string Suffix 60 | { 61 | get 62 | { 63 | return _Suffix; 64 | } 65 | set 66 | { 67 | _Suffix = value; 68 | } 69 | } 70 | 71 | //合并相同列(list中) 72 | 73 | //WrapMode(自动列宽,自动换行) 74 | 75 | //列宽 76 | 77 | private ExportAttribute(string prefix="",string suffix="") 78 | { 79 | _Prefix = prefix ?? ""; 80 | _Suffix = suffix ?? ""; 81 | } 82 | 83 | public ExportAttribute(string name,int index=0, string prefix = "", string suffix = "") 84 | { 85 | _Name = name ?? "" ; 86 | _SortIndex = index; 87 | _Prefix = prefix ?? ""; 88 | _Suffix = suffix ?? ""; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /ExcelCake.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33723.286 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExcelCake.Example", "ExcelCake.Example\ExcelCake.Example.csproj", "{411E802C-5397-45F2-A2C5-3C558B9320AE}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{C6A10CBF-67E6-4A82-9266-F5DD6FB16580}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExcelCake.Test", "ExcelCake.Test\ExcelCake.Test.csproj", "{CC62F6CE-A9C4-4759-9314-1CEB3E957900}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelCake", "ExcelCake\ExcelCake.csproj", "{EF08BCAB-BA35-4543-AD03-B85BB2B1ECA9}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {411E802C-5397-45F2-A2C5-3C558B9320AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {411E802C-5397-45F2-A2C5-3C558B9320AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {411E802C-5397-45F2-A2C5-3C558B9320AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {411E802C-5397-45F2-A2C5-3C558B9320AE}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {CC62F6CE-A9C4-4759-9314-1CEB3E957900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {CC62F6CE-A9C4-4759-9314-1CEB3E957900}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {CC62F6CE-A9C4-4759-9314-1CEB3E957900}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {CC62F6CE-A9C4-4759-9314-1CEB3E957900}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {EF08BCAB-BA35-4543-AD03-B85BB2B1ECA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {EF08BCAB-BA35-4543-AD03-B85BB2B1ECA9}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {EF08BCAB-BA35-4543-AD03-B85BB2B1ECA9}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {EF08BCAB-BA35-4543-AD03-B85BB2B1ECA9}.Release|Any CPU.Build.0 = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {69687E7A-2532-4DA0-BCA0-F8A1BD1B07B7} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Attribute/ImportEntityAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | /// 9 | /// 导入特性,标注类的导入信息 10 | /// 11 | [AttributeUsage(AttributeTargets.Class)] 12 | public class ImportEntityAttribute: Attribute 13 | { 14 | private int _TitleRowIndex; 15 | private int _HeadRowIndex; 16 | private int _DataRowIndex; 17 | 18 | /// 19 | /// 标题行Index 20 | /// 21 | public int TitleRowIndex 22 | { 23 | get 24 | { 25 | return _TitleRowIndex; 26 | } 27 | set 28 | { 29 | _TitleRowIndex = value; 30 | } 31 | } 32 | 33 | /// 34 | /// 列头行Index 35 | /// 36 | public int HeadRowIndex 37 | { 38 | get 39 | { 40 | return _HeadRowIndex; 41 | } 42 | set 43 | { 44 | _HeadRowIndex = value; 45 | } 46 | } 47 | 48 | /// 49 | /// 数据行Index 50 | /// 51 | public int DataRowIndex 52 | { 53 | get 54 | { 55 | return _DataRowIndex; 56 | } 57 | set 58 | { 59 | _DataRowIndex = value; 60 | } 61 | } 62 | 63 | public ImportEntityAttribute() 64 | { 65 | _TitleRowIndex = 0; 66 | _HeadRowIndex = 1; 67 | _DataRowIndex = 2; 68 | } 69 | 70 | public ImportEntityAttribute(int headRowIndex, int dataRowIndex) 71 | { 72 | _TitleRowIndex = 0; 73 | _HeadRowIndex = headRowIndex < 1 ? 1 : headRowIndex; 74 | _DataRowIndex = dataRowIndex < 2 ? 2 : dataRowIndex; 75 | } 76 | 77 | public ImportEntityAttribute(int titleRowIndex,int headRowIndex,int dataRowIndex) 78 | { 79 | _TitleRowIndex = titleRowIndex < 0 ? 0 : titleRowIndex; 80 | _HeadRowIndex = headRowIndex < 1 ? 1 : headRowIndex; 81 | _DataRowIndex = dataRowIndex < 2 ? 2 : dataRowIndex; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingField.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Xml; 7 | 8 | namespace ExcelCake.NoIntrusive 9 | { 10 | [Serializable] 11 | internal class TemplateSettingField : TemplateSettingBase 12 | { 13 | public string Field { set; get; } 14 | 15 | private TemplateSettingField() 16 | { 17 | 18 | } 19 | 20 | internal static TemplateSettingField Create(ExcelRangeBase cell) 21 | { 22 | var entity = new TemplateSettingField(); 23 | entity.CurrentCell = cell; 24 | entity.Content = cell.Value?.ToString() ?? ""; 25 | entity.AnalyseSetting(); 26 | return entity; 27 | } 28 | 29 | protected override void AnalyseSetting() 30 | { 31 | var cellValue = this.Content; 32 | 33 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 34 | if (arry.Length == 0) 35 | { 36 | return; 37 | } 38 | foreach (var item in arry) 39 | { 40 | if (item.IndexOf(":") > -1 && item.IndexOf(";") > -1) 41 | { 42 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 43 | if (settingItemArry.Length == 0) 44 | { 45 | continue; 46 | } 47 | 48 | foreach (var arryItem in settingItemArry) 49 | { 50 | var settingItem = arryItem.Split(':'); 51 | if (settingItem.Length < 2) 52 | { 53 | continue; 54 | } 55 | var key = settingItem[0]; 56 | var value = settingItem[1]; 57 | if (string.IsNullOrEmpty(key)) 58 | { 59 | continue; 60 | } 61 | 62 | switch (key.ToUpper()) 63 | { 64 | case "FIELD": 65 | { 66 | this.Field = value.ToUpper(); 67 | } 68 | break; 69 | } 70 | } 71 | 72 | } 73 | } 74 | 75 | this.ScopeRange = this.CurrentCell; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingRangeGrid.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | [Serializable] 10 | internal class TemplateSettingRangeGrid : TemplateSettingRange 11 | { 12 | public List UnderGrid { get; set; } 13 | 14 | private TemplateSettingRangeGrid() 15 | { 16 | 17 | } 18 | 19 | internal static TemplateSettingRangeGrid Create(ExcelRangeBase cell) 20 | { 21 | var entity = new TemplateSettingRangeGrid(); 22 | entity.Fields = new List(); 23 | entity.UnderGrid = new List(); 24 | entity.Content = cell.Value?.ToString() ?? ""; 25 | entity.CurrentCell = cell; 26 | entity.AnalyseSetting(); 27 | return entity; 28 | } 29 | 30 | protected override void AnalyseSetting() 31 | { 32 | var cellValue = this.Content; 33 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 34 | if (arry.Length == 0) 35 | { 36 | return; 37 | } 38 | foreach (var item in arry) 39 | { 40 | if (item.IndexOf(":") > -1 && item.IndexOf(";") > -1) 41 | { 42 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 43 | if (settingItemArry.Length == 0) 44 | { 45 | continue; 46 | } 47 | 48 | foreach (var arryItem in settingItemArry) 49 | { 50 | var settingItem = arryItem.Split(':'); 51 | if (settingItem.Length < 2) 52 | { 53 | continue; 54 | } 55 | var key = settingItem[0]; 56 | var value = settingItem[1]; 57 | if (string.IsNullOrEmpty(key)) 58 | { 59 | continue; 60 | } 61 | 62 | switch (key.ToUpper()) 63 | { 64 | case "DATASOURCE": { this.DataSource = value.ToUpper(); } break; 65 | case "ADDRESSLEFTTOP": { this.AddressLeftTop = value.ToUpper(); } break; 66 | case "ADDRESSRIGHTBOTTOM": { this.AddressRightBottom = value.ToUpper(); } break; 67 | } 68 | } 69 | } 70 | 71 | ExcelCommon.CalcRowCol(this.AddressLeftTop, out int fromRow, out int fromCol); 72 | ExcelCommon.CalcRowCol(this.AddressRightBottom, out int toRow, out int toCol); 73 | this.FromRow = fromRow; 74 | this.FromCol = fromCol; 75 | this.ToRow = toRow; 76 | this.ToCol = toCol; 77 | this.ScopeRange = this.CurrentCell.Worksheet.Cells[this.FromRow, this.FromCol, this.ToRow, this.ToCol]; 78 | } 79 | } 80 | 81 | internal override void Draw(ExcelWorksheet workSheet, ExcelObject dataSource) 82 | { 83 | throw new NotImplementedException(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ExportExcelSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Drawing; 7 | 8 | namespace ExcelCake.Intrusive 9 | { 10 | public class ExportExcelSetting 11 | { 12 | public List ExportColumns { set; get; } 13 | public ExportStyle ExportStyle { set; get; } 14 | public List> MergeList { set; get; } 15 | 16 | private ExportExcelSetting() 17 | { 18 | 19 | } 20 | 21 | public ExportExcelSetting(Type type) 22 | { 23 | ExportStyle = new ExportStyle(); 24 | ExportColumns = new List(); 25 | MergeList = new List>(); 26 | if (type == null) 27 | { 28 | return; 29 | } 30 | 31 | #region 组织表头 32 | var classAttrArry = type.GetCustomAttributes(typeof(ExportEntityAttribute), true); 33 | if (classAttrArry == null || classAttrArry.Length == 0) 34 | { 35 | return; 36 | } 37 | 38 | var exportEntity = (ExportEntityAttribute)classAttrArry[0]; 39 | ExportStyle.Title = exportEntity.Title; 40 | ExportStyle.HeadColor = ColorTranslator.FromHtml(exportEntity.HeadColor.ToString()); 41 | ExportStyle.TitleColor = ColorTranslator.FromHtml(exportEntity.TitleColor.ToString()); 42 | ExportStyle.TitleFontSize = exportEntity.TitleFontSize; 43 | ExportStyle.IsTitleBold = exportEntity.IsTitleBold; 44 | ExportStyle.TitleColumnSpan = exportEntity.TitleColumnSpan; 45 | ExportStyle.HeadFontSize = exportEntity.HeadFontSize; 46 | ExportStyle.IsHeadBold = exportEntity.IsHeadBold; 47 | ExportStyle.ContentColor = ColorTranslator.FromHtml(exportEntity.ContentColor.ToString()); 48 | ExportStyle.ContentFontSize = exportEntity.ContentFontSize; 49 | ExportStyle.IsContentBold = exportEntity.IsContentBold; 50 | var properties = type.GetProperties(); 51 | 52 | foreach (var proper in properties) 53 | { 54 | var exportAttrArry = proper.GetCustomAttributes(typeof(ExportAttribute), true); 55 | if (exportAttrArry != null && exportAttrArry.Length > 0) 56 | { 57 | var column = new ExportColumn(proper); 58 | if (column != null) 59 | { 60 | ExportColumns.Add(column); 61 | } 62 | } 63 | } 64 | #endregion 65 | 66 | #region 排序 67 | //ExportColumns.Sort((a, b) => a.Index.CompareTo(b.Index)); 68 | var groupTemp = ExportColumns.GroupBy(o => o.MergeText); 69 | ExportColumns = new List(); 70 | foreach(var item in groupTemp) 71 | { 72 | var mergeList = item.ToList(); 73 | if (mergeList.Count == 1) 74 | { 75 | mergeList.First().MergeText = ""; 76 | } 77 | else 78 | { 79 | mergeList.Sort((a, b) => a.Index.CompareTo(b.Index)); 80 | MergeList.Add(new KeyValuePair(item.Key, item.Count())); 81 | } 82 | 83 | ExportColumns.AddRange(mergeList); 84 | } 85 | #endregion 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Attribute/ImportAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | /// 9 | /// 导入特性,标注导入的属性 10 | /// 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public class ImportAttribute: Attribute 13 | { 14 | private string _Name; 15 | private bool _IsUseTempField; 16 | private string _TempField; 17 | private string _Prefix; 18 | private string _Suffix; 19 | private string _DataVerReg; 20 | private bool _IsRegFailThrowException; 21 | 22 | /// 23 | /// 导入名称 24 | /// 25 | public string Name 26 | { 27 | get 28 | { 29 | return _Name; 30 | } 31 | } 32 | 33 | /// 34 | /// 是否使用临时字段 35 | /// 36 | public bool IsUseTempField 37 | { 38 | get 39 | { 40 | return _IsUseTempField; 41 | } 42 | set 43 | { 44 | _IsUseTempField = value; 45 | } 46 | } 47 | 48 | /// 49 | /// 临时字段 50 | /// 51 | public string TempField 52 | { 53 | get 54 | { 55 | return _TempField; 56 | } 57 | set 58 | { 59 | _TempField = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 前缀 65 | /// 66 | public string Prefix 67 | { 68 | get 69 | { 70 | return _Prefix; 71 | } 72 | set 73 | { 74 | _Prefix = value; 75 | } 76 | } 77 | 78 | /// 79 | /// 后缀 80 | /// 81 | public string Suffix 82 | { 83 | get 84 | { 85 | return _Suffix; 86 | } 87 | set 88 | { 89 | _Suffix = value; 90 | } 91 | } 92 | 93 | /// 94 | /// 数据校验正则 95 | /// 96 | public string DataVerReg 97 | { 98 | get 99 | { 100 | return _DataVerReg; 101 | } 102 | set 103 | { 104 | _DataVerReg = value; 105 | } 106 | } 107 | 108 | /// 109 | /// 正则验证失败是否抛出异常 110 | /// 111 | public bool IsRegFailThrowException 112 | { 113 | get 114 | { 115 | return _IsRegFailThrowException; 116 | } 117 | set 118 | { 119 | _IsRegFailThrowException = value; 120 | } 121 | } 122 | 123 | //数据校验 124 | 125 | private ImportAttribute() 126 | { 127 | _IsUseTempField = false; 128 | } 129 | 130 | public ImportAttribute(string name, string dataVerReg = "", bool isRegFailThrowException = false,string prefix="",string suffix="") 131 | { 132 | _Name = name??""; 133 | _IsUseTempField = false; 134 | _DataVerReg = dataVerReg??""; 135 | _IsRegFailThrowException = isRegFailThrowException; 136 | _Prefix = prefix??""; 137 | _Suffix = suffix ?? ""; 138 | } 139 | 140 | public ImportAttribute(string name,bool isUseTempField, string tempField, string prefix = "", string suffix = "") 141 | { 142 | _Name = name??""; 143 | _IsUseTempField = isUseTempField; 144 | _TempField = tempField??""; 145 | _Prefix = prefix ?? ""; 146 | _Suffix = suffix ?? ""; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingRangeFree.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | [Serializable] 10 | internal class TemplateSettingRangeFree : TemplateSettingRange 11 | { 12 | private TemplateSettingRangeFree() 13 | { 14 | 15 | } 16 | 17 | internal static TemplateSettingRangeFree Create(ExcelRangeBase cell) 18 | { 19 | var entity = new TemplateSettingRangeFree(); 20 | entity.Fields = new List(); 21 | entity.Content = cell.Value?.ToString() ?? ""; 22 | entity.CurrentCell = cell; 23 | entity.AnalyseSetting(); 24 | return entity; 25 | } 26 | 27 | protected override void AnalyseSetting() 28 | { 29 | var cellValue = this.Content; 30 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 31 | if (arry.Length == 0) 32 | { 33 | return; 34 | } 35 | foreach (var item in arry) 36 | { 37 | if (item.IndexOf(":") > -1 && item.IndexOf(";") > -1) 38 | { 39 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 40 | if (settingItemArry.Length == 0) 41 | { 42 | continue; 43 | } 44 | 45 | foreach (var arryItem in settingItemArry) 46 | { 47 | var settingItem = arryItem.Split(':'); 48 | if (settingItem.Length < 2) 49 | { 50 | continue; 51 | } 52 | var key = settingItem[0]; 53 | var value = settingItem[1]; 54 | if (string.IsNullOrEmpty(key)) 55 | { 56 | continue; 57 | } 58 | 59 | switch (key.ToUpper()) 60 | { 61 | case "DATASOURCE": { this.DataSource = value.ToUpper(); } break; 62 | case "ADDRESSLEFTTOP": { this.AddressLeftTop = value.ToUpper(); } break; 63 | case "ADDRESSRIGHTBOTTOM": { this.AddressRightBottom = value.ToUpper(); } break; 64 | } 65 | } 66 | } 67 | //var cellValueStr = cell.Value?.ToString() ?? ""; 68 | //cell.Value = cellValueStr.Replace("{" + item + "}", ""); 69 | } 70 | 71 | ExcelCommon.CalcRowCol(this.AddressLeftTop, out int fromRow, out int fromCol); 72 | ExcelCommon.CalcRowCol(this.AddressRightBottom, out int toRow, out int toCol); 73 | this.FromRow = fromRow; 74 | this.FromCol = fromCol; 75 | this.ToRow = toRow; 76 | this.ToCol = toCol; 77 | this.ScopeRange = this.CurrentCell.Worksheet.Cells[this.FromRow, this.FromCol, this.ToRow, this.ToCol]; 78 | } 79 | 80 | internal override void Draw(ExcelWorksheet workSheet,ExcelObject dataSource) 81 | { 82 | if (string.IsNullOrEmpty(this.AddressLeftTop) || string.IsNullOrEmpty(this.AddressRightBottom)) 83 | { 84 | return; 85 | } 86 | ExcelRange range = workSheet.Cells[this.AddressLeftTop + "," + this.AddressRightBottom]; 87 | 88 | if (!dataSource.DataEntity.Keys.Contains(this.DataSource)) 89 | { 90 | return; 91 | } 92 | var data = dataSource.DataEntity[this.DataSource]; 93 | 94 | foreach (var field in Fields) 95 | { 96 | var fieldName = field.Field; 97 | var value = field.CurrentCell.Value?.ToString() ?? ""; 98 | value = value.Replace(field.Content, ""); 99 | object fieldData = null; 100 | if (data.Keys.Contains(field.Field)) 101 | { 102 | fieldData = data[field.Field]; 103 | } 104 | field.CurrentCell.Value = value + fieldData; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/DataObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | 9 | namespace ExcelCake.NoIntrusive 10 | { 11 | public class ExcelObject 12 | { 13 | private static Dictionary> _PropertyInfo = new Dictionary>(); 14 | 15 | public Dictionary> DataEntity { get; private set; } 16 | public Dictionary>> DataList { get; private set; } 17 | 18 | public ExcelObject(object dataSource) 19 | { 20 | AnalysisDataSource(dataSource); 21 | } 22 | 23 | public ExcelObject(DataSet dataSource) 24 | { 25 | AnalysisDataSource(dataSource); 26 | } 27 | 28 | /// 29 | /// 30 | /// 31 | /// 32 | private void AnalysisDataSource(object model) 33 | { 34 | DataEntity = new Dictionary>(); 35 | DataEntity.Add(string.Empty, new Dictionary()); 36 | DataList = new Dictionary>>(); 37 | 38 | if (model == null) 39 | { 40 | return; 41 | } 42 | 43 | Type modelType = model.GetType(); 44 | var tps = GetProperty(modelType); 45 | 46 | foreach (var pn in tps.Keys) 47 | { 48 | var tp = tps[pn]; 49 | var tpv = tp.GetValue(model, null); 50 | 51 | if (tpv == null) 52 | { 53 | DataEntity[string.Empty].Add(pn, null); 54 | continue; 55 | } 56 | var tpt = tpv.GetType(); 57 | 58 | if (tpt.Name.StartsWith("List") == true) 59 | { 60 | DataList.Add(pn.ToUpper(), new Dictionary>()); 61 | var tpvs = tpv as IEnumerable; 62 | foreach (var tpvi in tpvs) 63 | { 64 | var tpp = GetProperty(tpvi.GetType()); 65 | foreach (var tppp in tpp.Values) 66 | { 67 | if (DataList[pn.ToUpper()].ContainsKey(tppp.Name.ToUpper()) == false) DataList[pn.ToUpper()].Add(tppp.Name.ToUpper(), new List()); 68 | DataList[pn.ToUpper()][tppp.Name.ToUpper()].Add(tppp.GetValue(tpvi, null)); 69 | } 70 | } 71 | } 72 | else if (tpt.FullName.StartsWith("System.") == true) 73 | { 74 | DataEntity[string.Empty].Add(pn.ToUpper(), tpv); 75 | } 76 | else 77 | { 78 | DataEntity.Add(pn.ToUpper(), new Dictionary()); 79 | var tpp = GetProperty(tpt); 80 | foreach (var tppp in tpp.Values) 81 | { 82 | DataEntity[pn.ToUpper()].Add(tppp.Name.ToUpper(), tppp.GetValue(tpv, null)); 83 | } 84 | } 85 | } 86 | } 87 | 88 | /// 89 | /// 90 | /// 91 | /// 92 | private void AnalysisDataSource(DataSet dataSource) 93 | { 94 | DataEntity = new Dictionary>(); 95 | DataEntity.Add(string.Empty, new Dictionary()); 96 | DataList = new Dictionary>>(); 97 | 98 | if (dataSource == null || dataSource.Tables == null) 99 | { 100 | return; 101 | } 102 | 103 | foreach (DataTable t in dataSource.Tables) 104 | { 105 | if (t.Rows.Count == 1) 106 | { 107 | DataEntity.Add(t.TableName.ToUpper(), new Dictionary()); 108 | for (int c = 0; c < t.Columns.Count; c++) 109 | { 110 | DataEntity[t.TableName.ToUpper()].Add(t.Columns[c].ColumnName.ToUpper(), t.Rows[0][c]); 111 | } 112 | } 113 | DataList.Add(t.TableName.ToUpper(), new Dictionary>()); 114 | for (int c = 0; c < t.Columns.Count; c++) 115 | { 116 | DataList[t.TableName.ToUpper()].Add(t.Columns[c].ColumnName.ToUpper(), new List()); 117 | } 118 | for (int r = 0; r < t.Rows.Count; r++) 119 | { 120 | for (int c = 0; c < t.Columns.Count; c++) 121 | { 122 | DataList[t.TableName.ToUpper()][t.Columns[c].ColumnName.ToUpper()].Add(t.Rows[r][c]); 123 | } 124 | } 125 | } 126 | } 127 | 128 | private static Dictionary GetProperty(Type type) 129 | { 130 | if (_PropertyInfo.ContainsKey(type) == true) 131 | { 132 | return _PropertyInfo[type]; 133 | } 134 | _PropertyInfo.Add(type, new Dictionary()); 135 | 136 | var tps = type.GetProperties(); 137 | for (int i = 0; i < tps.Length; i++) 138 | { 139 | _PropertyInfo[type].Add(tps[i].Name, tps[i]); 140 | } 141 | return _PropertyInfo[type]; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /ExcelCake/ExcelCommon.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace ExcelCake 9 | { 10 | public static class ExcelCommon 11 | { 12 | /// 13 | /// 设置单元格样式 14 | /// 15 | /// 16 | /// 17 | public static void HandleCellStyle(ExcelRangeBase settingCell, ExcelRangeBase newCell) 18 | { 19 | if (settingCell == null || newCell == null) 20 | { 21 | return; 22 | } 23 | newCell.Style.HorizontalAlignment = settingCell.Style.HorizontalAlignment; 24 | newCell.Style.VerticalAlignment = settingCell.Style.VerticalAlignment; 25 | 26 | // 27 | newCell.Style.Font.Bold = settingCell.Style.Font.Bold;//字体为粗体 28 | //field.CurrentCell.Offset(i, 0).Style.Font.Color.SetColor();//字体颜色 29 | newCell.Style.Font.Name = settingCell.Style.Font.Name;//字体 30 | newCell.Style.Font.Size = settingCell.Style.Font.Size;//字体大小 31 | newCell.Style.Fill.PatternType = settingCell.Style.Fill.PatternType; 32 | //field.CurrentCell.Offset(i, 0).Style.Fill.BackgroundColor.SetColor();//设置单元格背 33 | //field.CurrentCell.Offset(i, 0).Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191));//设置单元格所有边框 34 | newCell.Style.Border.Left.Style = settingCell.Style.Border.Left.Style; 35 | newCell.Style.Border.Right.Style = settingCell.Style.Border.Right.Style; 36 | newCell.Style.Border.Top.Style = settingCell.Style.Border.Top.Style; 37 | newCell.Style.Border.Bottom.Style = settingCell.Style.Border.Bottom.Style; 38 | newCell.Style.ShrinkToFit = settingCell.Style.ShrinkToFit;//单元格自动适应大小 39 | //workSheet.Row(row + i).Height = workSheet.Row(row).Height;//设置行高 40 | //workSheet.Row(row + i).CustomHeight = workSheet.Row(row).CustomHeight;//自动调整行高 41 | } 42 | 43 | /// 44 | /// 判断单元格是否在区域内 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// 50 | public static bool IsCellInRange(string rangeLeftTopAddress, string rangeRightBottomAddress, ExcelRangeBase cell) 51 | { 52 | bool isCellInRange = false; 53 | if (rangeLeftTopAddress.Length < 2 || rangeRightBottomAddress.Length < 2) 54 | { 55 | return isCellInRange; 56 | } 57 | var rangeLeftTopCol = 0; 58 | var rangeLeftTopRow = 0; 59 | var rangeRightBottomCol = 0; 60 | var rangeRightBottomRow = 0; 61 | var cellCol = 0; 62 | var cellRow = 0; 63 | 64 | CalcRowCol(rangeLeftTopAddress, out rangeLeftTopRow, out rangeLeftTopCol); 65 | CalcRowCol(rangeRightBottomAddress, out rangeRightBottomRow, out rangeRightBottomCol); 66 | CalcRowCol(cell.Address, out cellRow, out cellCol); 67 | if (cellRow >= rangeLeftTopRow && cellRow <= rangeRightBottomRow && cellCol >= rangeLeftTopCol && cellCol <= rangeRightBottomCol) 68 | { 69 | isCellInRange = true; 70 | } 71 | 72 | return isCellInRange; 73 | } 74 | 75 | /// 76 | /// 判断单元格是否在区域内 77 | /// 78 | /// 79 | /// 80 | /// 81 | /// 82 | /// 83 | /// 84 | public static bool IsCellInRange(int fromRow, int fromCol, int toRow, int toCol, ExcelRangeBase cell) 85 | { 86 | bool isCellInRange = false; 87 | 88 | var cellCol = 0; 89 | var cellRow = 0; 90 | 91 | CalcRowCol(cell.Address, out cellRow, out cellCol); 92 | if (cellRow >= fromRow && cellRow <= toRow && cellCol >= fromCol && cellCol <= toCol) 93 | { 94 | isCellInRange = true; 95 | } 96 | 97 | return isCellInRange; 98 | } 99 | 100 | 101 | /// 102 | /// 字母列转换为数字列 103 | /// 104 | /// 105 | /// 106 | /// 107 | public static void CalcRowCol(string cellAddress, out int row, out int col) 108 | { 109 | if (string.IsNullOrWhiteSpace(cellAddress)) 110 | { 111 | throw new ImportFormatException("单元格地址非法"); 112 | } 113 | 114 | string rowStr = ""; 115 | string colStr = ""; 116 | foreach (var item in cellAddress) 117 | { 118 | if (char.IsDigit(item)) 119 | { 120 | rowStr += item; 121 | } 122 | else 123 | { 124 | colStr += item; 125 | } 126 | } 127 | int.TryParse(rowStr, out row); 128 | 129 | col = 1; 130 | if (Regex.IsMatch(colStr.ToUpper(), @"[A-Z]+")) 131 | { 132 | int index = 0; 133 | char[] chars = colStr.ToUpper().ToCharArray(); 134 | for (int i = 0; i < chars.Length; i++) 135 | { 136 | index += ((int)chars[i] - (int)'A' + 1) * (int)Math.Pow(26, chars.Length - i - 1); 137 | } 138 | //col = index - 1; 139 | col = index; 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingSheet.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using OfficeOpenXml.ConditionalFormatting; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace ExcelCake.NoIntrusive 9 | { 10 | internal class TemplateSettingSheet 11 | { 12 | private List _FreeSettingList; 13 | private List _GridSettingList; 14 | //private List _ChartSettingList; 15 | private List _FieldSettingList; 16 | public List FreeSettingList 17 | { 18 | get 19 | { 20 | return _FreeSettingList; 21 | } 22 | } 23 | 24 | public List GridSettingList 25 | { 26 | get 27 | { 28 | return _GridSettingList; 29 | } 30 | } 31 | 32 | //public List ChartSettingList 33 | //{ 34 | // get 35 | // { 36 | // return _ChartSettingList; 37 | // } 38 | //} 39 | 40 | private TemplateSettingSheet() 41 | { 42 | 43 | } 44 | 45 | public TemplateSettingSheet(ExcelWorksheet sheet) 46 | { 47 | _FreeSettingList = new List(); 48 | _GridSettingList = new List(); 49 | //_ChartSettingList = new List(); 50 | _FieldSettingList = new List(); 51 | 52 | if (sheet == null || sheet.Cells.Count() <= 0) 53 | { 54 | return; 55 | } 56 | foreach (var cell in sheet.Cells) 57 | { 58 | var cellValue = cell.Value?.ToString() ?? ""; 59 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 60 | if (arry.Length == 0) 61 | { 62 | continue; 63 | } 64 | 65 | foreach (var item in arry) 66 | { 67 | if (item.IndexOf(":") > -1 && item.IndexOf(";") > -1) 68 | { 69 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 70 | if (settingItemArry.Length == 0) 71 | { 72 | continue; 73 | } 74 | 75 | foreach(var settingItem in settingItemArry) 76 | { 77 | if (settingItem.ToUpper().IndexOf("TYPE") <0 ) 78 | { 79 | continue; 80 | } 81 | 82 | var arrItem = settingItem.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries); 83 | if (arrItem.Length < 2) 84 | { 85 | continue; 86 | } 87 | 88 | var key = arrItem[0]; 89 | var value = arrItem[1]; 90 | 91 | switch (value.ToUpper()) 92 | { 93 | case "FREE": { 94 | var freeItem = TemplateSettingRangeFree.Create(cell); 95 | _FreeSettingList.Add(freeItem); 96 | } break; 97 | case "GRID": 98 | { 99 | var gridItem =TemplateSettingRangeGrid.Create(cell); 100 | _GridSettingList.Add(gridItem); 101 | } 102 | break; 103 | case "CHART": 104 | { 105 | //var chartItem = TemplateSettingRangeChart.Create(cell); 106 | //_ChartSettingList.Add(chartItem); 107 | } 108 | break; 109 | case "VALUE": 110 | { 111 | var fieldItem = TemplateSettingField.Create(cell); 112 | _FieldSettingList.Add(fieldItem); 113 | } 114 | break; 115 | } 116 | } 117 | } 118 | var cellValueStr = cell.Value?.ToString() ?? ""; 119 | cell.Value = cellValueStr.Replace("{" + item + "}", ""); 120 | } 121 | 122 | //自由格式 123 | foreach(var free in _FreeSettingList) 124 | { 125 | foreach(var field in _FieldSettingList) 126 | { 127 | var isContain = ExcelCommon.IsCellInRange(free.AddressLeftTop, free.AddressRightBottom, field.CurrentCell); 128 | 129 | if (isContain) 130 | { 131 | free.Fields.Add(field); 132 | } 133 | } 134 | } 135 | 136 | //表格 137 | foreach(var grid in _GridSettingList) 138 | { 139 | foreach (var field in _FieldSettingList) 140 | { 141 | var isContain = ExcelCommon.IsCellInRange(grid.AddressLeftTop, grid.AddressRightBottom, field.CurrentCell); 142 | 143 | if (isContain) 144 | { 145 | grid.Fields.Add(field); 146 | } 147 | } 148 | } 149 | 150 | 151 | //图表 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Attribute/ExportEntityAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Web; 6 | 7 | namespace ExcelCake.Intrusive 8 | { 9 | /// 10 | /// 导出特性,标注类的导出信息 11 | /// 12 | [AttributeUsage(AttributeTargets.Class)] 13 | public class ExportEntityAttribute:Attribute 14 | { 15 | private EnumColor _TitleColor; 16 | 17 | private string _Title; 18 | 19 | private int _TitleFontSize; 20 | 21 | private bool _IsTitleBold; 22 | 23 | private int _TitleColumnSpan; 24 | 25 | private EnumColor _HeadColor; 26 | 27 | private int _HeadFontSize; 28 | 29 | private bool _IsHeadBold; 30 | 31 | private EnumColor _ContentColor; 32 | 33 | private int _ContentFontSize; 34 | 35 | private bool _IsContentBold; 36 | 37 | //列高 38 | 39 | //是否自动换行 40 | 41 | /// 42 | /// 标题背景颜色 43 | /// 44 | public EnumColor TitleColor 45 | { 46 | get 47 | { 48 | return _TitleColor; 49 | } 50 | } 51 | 52 | /// 53 | /// 标题文本 54 | /// 55 | public string Title 56 | { 57 | get 58 | { 59 | return _Title; 60 | } 61 | } 62 | 63 | /// 64 | /// 标题文本字号 65 | /// 66 | public int TitleFontSize 67 | { 68 | get 69 | { 70 | return _TitleFontSize; 71 | } 72 | } 73 | 74 | /// 75 | /// 标题是否粗体 76 | /// 77 | public bool IsTitleBold 78 | { 79 | get 80 | { 81 | return _IsTitleBold; 82 | } 83 | } 84 | 85 | /// 86 | /// 标题合并列数 87 | /// 88 | public int TitleColumnSpan 89 | { 90 | get 91 | { 92 | return _TitleColumnSpan; 93 | } 94 | } 95 | 96 | /// 97 | /// 列头背景颜色 98 | /// 99 | public EnumColor HeadColor 100 | { 101 | get 102 | { 103 | return _HeadColor; 104 | } 105 | } 106 | 107 | /// 108 | /// 列头字号 109 | /// 110 | public int HeadFontSize 111 | { 112 | get 113 | { 114 | return _HeadFontSize; 115 | } 116 | } 117 | 118 | /// 119 | /// 列头是否粗体 120 | /// 121 | public bool IsHeadBold 122 | { 123 | get 124 | { 125 | return _IsHeadBold; 126 | } 127 | } 128 | 129 | /// 130 | /// 内容背景色 131 | /// 132 | public EnumColor ContentColor 133 | { 134 | get 135 | { 136 | return _ContentColor; 137 | } 138 | } 139 | 140 | /// 141 | /// 内容字号 142 | /// 143 | public int ContentFontSize 144 | { 145 | get 146 | { 147 | return _ContentFontSize; 148 | } 149 | } 150 | 151 | /// 152 | /// 内容是否粗体 153 | /// 154 | public bool IsContentBold 155 | { 156 | get 157 | { 158 | return _IsContentBold; 159 | } 160 | } 161 | 162 | private ExportEntityAttribute() 163 | { 164 | 165 | } 166 | 167 | public ExportEntityAttribute(string title = "", int titleFontSize = 14, int headFontSize = 12, int contentFontSize = 10, bool isTitleBold = true, bool isHeadBold = true, bool isContentBold = false,int titleColumnSpan=0) 168 | { 169 | this._TitleColor = EnumColor.White; 170 | this._HeadColor = EnumColor.White; 171 | this._ContentColor = EnumColor.White; 172 | this._Title = title; 173 | this._TitleFontSize = titleFontSize; 174 | this._HeadFontSize = headFontSize; 175 | this._ContentFontSize = contentFontSize; 176 | this._IsTitleBold = isTitleBold; 177 | this._IsHeadBold = isHeadBold; 178 | this._IsContentBold = isContentBold; 179 | this._TitleColumnSpan = titleColumnSpan; 180 | } 181 | 182 | public ExportEntityAttribute(EnumColor headColor, string title="", int titleFontSize = 14, int headFontSize = 12, int contentFontSize = 10, bool isTitleBold = true, bool isHeadBold = true, bool isContentBold = false, int titleColumnSpan = 0) 183 | { 184 | this._TitleColor = EnumColor.White; 185 | this._HeadColor = headColor; 186 | this._ContentColor = EnumColor.White; 187 | this._Title = title; 188 | this._TitleFontSize = titleFontSize; 189 | this._HeadFontSize = headFontSize; 190 | this._ContentFontSize = contentFontSize; 191 | this._IsTitleBold = isTitleBold; 192 | this._IsHeadBold = isHeadBold; 193 | this._IsContentBold = isContentBold; 194 | this._TitleColumnSpan = titleColumnSpan; 195 | } 196 | 197 | public ExportEntityAttribute(EnumColor titleColor, EnumColor headColor, string title="", int titleFontSize = 14, int headFontSize = 12, int contentFontSize = 10, bool isTitleBold = true, bool isHeadBold = true, bool isContentBold = false, int titleColumnSpan = 0) 198 | { 199 | this._TitleColor = titleColor; 200 | this._HeadColor = headColor; 201 | this._ContentColor = EnumColor.White; 202 | this._Title = title; 203 | this._TitleFontSize = titleFontSize; 204 | this._HeadFontSize = headFontSize; 205 | this._ContentFontSize = contentFontSize; 206 | this._IsTitleBold = isTitleBold; 207 | this._IsHeadBold = isHeadBold; 208 | this._IsContentBold = isContentBold; 209 | this._TitleColumnSpan = titleColumnSpan; 210 | } 211 | 212 | public ExportEntityAttribute(EnumColor titleColor, EnumColor headColor, EnumColor contentColor, string title="", int titleFontSize = 14, int headFontSize = 12, int contentFontSize = 10, bool isTitleBold = true, bool isHeadBold = true, bool isContentBold = false, int titleColumnSpan = 0) 213 | { 214 | this._TitleColor = titleColor; 215 | this._HeadColor = headColor; 216 | this._ContentColor = contentColor; 217 | this._Title = title; 218 | this._TitleFontSize = titleFontSize; 219 | this._HeadFontSize = headFontSize; 220 | this._ContentFontSize = contentFontSize; 221 | this._IsTitleBold = isTitleBold; 222 | this._IsHeadBold = isHeadBold; 223 | this._IsContentBold = isContentBold; 224 | this._TitleColumnSpan = titleColumnSpan; 225 | } 226 | } 227 | } -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSettingSheet.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | internal class TemplateSettingSheet 10 | { 11 | private List _FreeSettingList; 12 | private List _GridSettingList; 13 | private List _FieldSettingList; 14 | 15 | public List FreeSettingList 16 | { 17 | get 18 | { 19 | return _FreeSettingList; 20 | } 21 | } 22 | 23 | public List GridSettingList 24 | { 25 | get 26 | { 27 | return _GridSettingList; 28 | } 29 | } 30 | 31 | public List FieldSettingList 32 | { 33 | get 34 | { 35 | return _FieldSettingList; 36 | } 37 | } 38 | 39 | private TemplateSettingSheet() 40 | { 41 | 42 | } 43 | 44 | public TemplateSettingSheet(ExcelWorksheet sheet) 45 | { 46 | _FreeSettingList = new List(); 47 | _GridSettingList = new List(); 48 | _FieldSettingList = new List(); 49 | 50 | if (sheet == null || sheet.Cells.Count() <= 0) 51 | { 52 | return; 53 | } 54 | foreach (var cell in sheet.Cells) 55 | { 56 | var cellValue = cell.Value?.ToString() ?? ""; 57 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 58 | if (arry.Length == 0) 59 | { 60 | continue; 61 | } 62 | foreach (var item in arry) 63 | { 64 | if ((item.IndexOf(":") > -1 && item.IndexOf(";") > -1)||item.StartsWith("@")) 65 | { 66 | var setting = new TemplateSettingRange(); 67 | if (item.StartsWith("@")) 68 | { 69 | setting.Type = "VALUE"; 70 | setting.Field = item.Replace("@","").ToUpper(); 71 | } 72 | else 73 | { 74 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 75 | if (settingItemArry.Length == 0) 76 | { 77 | continue; 78 | } 79 | 80 | foreach (var arryItem in settingItemArry) 81 | { 82 | var settingItem = arryItem.Split(':'); 83 | if (settingItem.Length < 2) 84 | { 85 | continue; 86 | } 87 | var key = settingItem[0]; 88 | var value = settingItem[1]; 89 | if (string.IsNullOrEmpty(key)) 90 | { 91 | continue; 92 | } 93 | 94 | switch (key.ToUpper()) 95 | { 96 | //旧语法 97 | case "TYPE": { setting.Type = value.ToUpper(); } break; 98 | case "DATASOURCE": { setting.DataSource = value.ToUpper(); } break; 99 | case "ADDRESSLEFTTOP": { setting.AddressLeftTop = value.ToUpper(); } break; 100 | case "ADDRESSRIGHTBOTTOM": { setting.AddressRightBottom = value.ToUpper(); } break; 101 | case "FIELD": { setting.Field = value.ToUpper(); } break; 102 | //新语法 103 | case "DATA": { setting.Type = "FREE"; setting.DataSource = value.ToUpper(); } break; 104 | case "LIST": { setting.Type = "GRID"; setting.DataSource = value.ToUpper(); } break; 105 | case "LT": { setting.AddressLeftTop = value.ToUpper(); } break; 106 | case "RB": { setting.AddressRightBottom = value.ToUpper(); } break; 107 | case "ADDRESS": { 108 | var addStr = value.ToUpper(); 109 | var addArr = addStr.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); 110 | if (settingItem.Length == 2) 111 | { 112 | setting.AddressLeftTop = addArr[0]; 113 | setting.AddressRightBottom = addArr[1]; 114 | } 115 | 116 | } break; 117 | } 118 | } 119 | } 120 | 121 | setting.CurrentCell = cell; 122 | setting.SettingString = "{" + item + "}"; 123 | if (string.IsNullOrEmpty(setting.Type)) 124 | { 125 | continue; 126 | } 127 | else if (setting.Type == "GRID") 128 | { 129 | ExcelCommon.CalcRowCol(setting.AddressLeftTop, out int fromRow, out int fromCol); 130 | ExcelCommon.CalcRowCol(setting.AddressRightBottom, out int toRow, out int toCol); 131 | setting.FromRow = fromRow; 132 | setting.FromCol = fromCol; 133 | setting.ToRow = toRow; 134 | setting.ToCol = toCol; 135 | _GridSettingList.Add(setting); 136 | } 137 | else if (setting.Type == "FREE") 138 | { 139 | ExcelCommon.CalcRowCol(setting.AddressLeftTop, out int fromRow, out int fromCol); 140 | ExcelCommon.CalcRowCol(setting.AddressRightBottom, out int toRow, out int toCol); 141 | setting.FromRow = fromRow; 142 | setting.FromCol = fromCol; 143 | setting.ToRow = toRow; 144 | setting.ToCol = toCol; 145 | _FreeSettingList.Add(setting); 146 | } 147 | else if (setting.Type == "VALUE") 148 | { 149 | //旧语法 150 | _FieldSettingList.Add(setting); 151 | } 152 | 153 | } 154 | var cellValueStr = cell.Value?.ToString() ?? ""; 155 | cell.Value = cellValueStr.Replace("{" + item + "}", ""); 156 | } 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Extension/ImportExtension.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | 10 | namespace ExcelCake.Intrusive 11 | { 12 | public static class ImportExtension 13 | { 14 | private static readonly string _DateTimeFormatStr = "yyyyMMddHHmmssfff"; 15 | 16 | public static void ImportToList(this IEnumerable list, FileInfo file, List importSheets=null,List noImportSheets=null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 17 | { 18 | 19 | if (!file.Exists) 20 | { 21 | list = new List(); 22 | return; 23 | } 24 | 25 | //读取excel 26 | using (ExcelPackage ep = new ExcelPackage(file)) 27 | { 28 | List sheets = ep.Workbook.Worksheets.ToList(); 29 | if (noImportSheets != null) 30 | { 31 | sheets = sheets.Where(p => !noImportSheets.Contains(p.Name)).ToList(); 32 | } 33 | 34 | if (importSheets != null) 35 | { 36 | sheets = sheets.Where(p => importSheets.Contains(p.Name)).ToList(); 37 | } 38 | 39 | if (!string.IsNullOrEmpty(noImportSheetsRegex)) 40 | { 41 | sheets = sheets.Where(p => !Regex.IsMatch(p.Name, noImportSheetsRegex)).ToList(); 42 | } 43 | 44 | if (!string.IsNullOrEmpty(importSheetsRegex)) 45 | { 46 | sheets = sheets.Where(p => Regex.IsMatch(p.Name, importSheetsRegex)).ToList(); 47 | } 48 | 49 | list = GetCollectionFromSheets(sheets); 50 | } 51 | } 52 | 53 | public static void ImportToList(this IEnumerable list, string filePath, List importSheets = null, List noImportSheets = null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 54 | { 55 | list.ImportToList(new FileInfo(filePath), importSheets, noImportSheets, importSheetsRegex, noImportSheetsRegex); 56 | } 57 | 58 | public static void ImportToAppendList(this IEnumerable list, FileInfo file, List importSheets = null, List noImportSheets = null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 59 | { 60 | List tempList = list?.ToList(); 61 | List tempList2 = new List(); 62 | if (file.Exists) 63 | { 64 | tempList2.ImportToList(file, importSheets, noImportSheets, importSheetsRegex, noImportSheetsRegex); 65 | if (tempList2.Count > 0) 66 | { 67 | tempList.AddRange(tempList2); 68 | } 69 | } 70 | 71 | list = tempList; 72 | } 73 | 74 | public static void ImportToAppendList(this IEnumerable list, string filePath, List importSheets = null, List noImportSheets = null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 75 | { 76 | list.ImportToAppendList(new FileInfo(filePath), importSheets, noImportSheets, importSheetsRegex, noImportSheetsRegex); 77 | } 78 | 79 | private static IEnumerable GetCollectionFromSheets(List sheets) where T : ExcelBase, new() 80 | { 81 | var list = new List(); 82 | 83 | if (sheets == null || sheets.Count == 0) 84 | { 85 | return list; 86 | } 87 | 88 | Type type = typeof(T); 89 | 90 | var importSetting = new ImportExcelSetting(type); 91 | if (importSetting.ImportColumns.Count > 0) 92 | { 93 | foreach(var item in sheets) 94 | { 95 | var sheetList = GetListFromWorksheet(item, importSetting); 96 | if (sheetList.Count>0) 97 | { 98 | list.AddRange(sheetList); 99 | } 100 | } 101 | } 102 | 103 | return list; 104 | } 105 | 106 | private static List GetListFromWorksheet(ExcelWorksheet sheet,ImportExcelSetting importSetting) where T : ExcelBase, new() 107 | { 108 | List list = new List(); 109 | if (sheet == null||sheet.Dimension == null) 110 | return list; 111 | 112 | Type entityType = typeof(T); 113 | List errorMessages = new List(); 114 | 115 | int maxColumnNum = sheet.Dimension.End.Column; 116 | int maxRowNum = sheet.Dimension.End.Row; 117 | 118 | for (int m = 1; m <= maxColumnNum; m++) 119 | { 120 | var cell = sheet.Cells[importSetting.ImportStyle.HeadRowIndex, m]; 121 | var importColumn = importSetting.ImportColumns.Where(o => o.Text == cell.Text?.Trim()).FirstOrDefault(); 122 | if (importColumn != null) 123 | { 124 | importColumn.ColumnIndex = m; 125 | } 126 | } 127 | 128 | for (int n = importSetting.ImportStyle.DataRowIndex; n <= maxRowNum; n++) 129 | { 130 | var entity = Activator.CreateInstance(); 131 | //?? 132 | entity.ExcelName = sheet.Workbook.Properties.Title; 133 | entity.SheetName = sheet.Name; 134 | entity.RowIndex = n; 135 | 136 | foreach (var item in importSetting.ImportColumns) 137 | { 138 | entity.ColumnIndex = item.ColumnIndex; 139 | var property = entityType.GetProperty(item.Name); 140 | 141 | #region 数据校验 142 | try 143 | { 144 | //??sheet.Cells[n, item.ColumnIndex].Text 145 | var value = sheet.Cells[n, item.ColumnIndex].Value; 146 | if (value != null && value.ToString() != "") 147 | { 148 | //if (item.IsConvert) 149 | //{ 150 | // var tempProperty = entityType.GetProperty(item.TempField); 151 | // if (tempProperty != null) 152 | // { 153 | // tempProperty.SetValue(entity, value, null); 154 | // } 155 | // else 156 | // { 157 | // var tempField = entityType.GetField(item.TempField); 158 | // if (tempField != null) 159 | // { 160 | // tempField.SetValue(entity, value); 161 | // } 162 | // } 163 | // continue; 164 | //} 165 | 166 | if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 167 | { 168 | if (value != null && value.ToString().Length > 0) 169 | { 170 | var tempValue = Convert.ChangeType(value, property.PropertyType.GetGenericArguments()[0]); 171 | property.SetValue(entity, tempValue, null); 172 | } 173 | } 174 | else 175 | { 176 | var tempValue = Convert.ChangeType(value, property.PropertyType); 177 | property.SetValue(entity, tempValue, null); 178 | } 179 | } 180 | 181 | } 182 | catch (Exception ex) 183 | { 184 | errorMessages.Add(string.Format("Excel{0}sheet:{1}第{2}行第{3}列【{4}】的值【{5}】不合法",entity.ExcelName,entity.SheetName, n, item.ColumnIndex, item.Text, sheet.Cells[n, item.ColumnIndex].Value)); 185 | } 186 | #endregion 187 | } 188 | 189 | list.Add(entity); 190 | } 191 | 192 | if (errorMessages.Count > 0) 193 | { 194 | throw new ImportFormatException(errorMessages.ToArray()); 195 | } 196 | 197 | return list; 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/ExcelHelper.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace ExcelCake.Intrusive 10 | { 11 | public class ExcelHelper 12 | { 13 | private static readonly string _DateTimeFormatStr = "yyyyMMddHHmmssfff"; 14 | 15 | public static IEnumerable GetList(FileInfo file, List importSheets = null, List noImportSheets = null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 16 | { 17 | IEnumerable list = new List(); 18 | 19 | if (!file.Exists) 20 | { 21 | return list; 22 | } 23 | 24 | //读取excel 25 | using (ExcelPackage ep = new ExcelPackage(file)) 26 | { 27 | List sheets = ep.Workbook.Worksheets.ToList(); 28 | if (noImportSheets != null) 29 | { 30 | sheets = sheets.Where(p => !noImportSheets.Contains(p.Name)).ToList(); 31 | } 32 | 33 | if (importSheets != null) 34 | { 35 | sheets = sheets.Where(p => importSheets.Contains(p.Name)).ToList(); 36 | } 37 | 38 | if (!string.IsNullOrEmpty(noImportSheetsRegex)) 39 | { 40 | sheets = sheets.Where(p => !Regex.IsMatch(p.Name, noImportSheetsRegex)).ToList(); 41 | } 42 | 43 | if (!string.IsNullOrEmpty(importSheetsRegex)) 44 | { 45 | sheets = sheets.Where(p => Regex.IsMatch(p.Name, importSheetsRegex)).ToList(); 46 | } 47 | 48 | list = GetCollectionFromSheets(sheets,ep.File.Name); 49 | } 50 | return list; 51 | } 52 | 53 | public static IEnumerable GetList(string filePath, List importSheets = null, List noImportSheets = null, string importSheetsRegex = "", string noImportSheetsRegex = "") where T : ExcelBase, new() 54 | { 55 | return GetList(new FileInfo(filePath), importSheets, noImportSheets, importSheetsRegex, noImportSheetsRegex); 56 | } 57 | 58 | private static IEnumerable GetCollectionFromSheets(List sheets,string excelName) where T : ExcelBase, new() 59 | { 60 | var list = new List(); 61 | 62 | if (sheets == null || sheets.Count == 0) 63 | { 64 | return list; 65 | } 66 | 67 | Type type = typeof(T); 68 | 69 | var importSetting = new ImportExcelSetting(type); 70 | if (importSetting.ImportColumns.Count > 0) 71 | { 72 | foreach (var item in sheets) 73 | { 74 | var sheetList = GetListFromWorksheet(item, importSetting, excelName); 75 | if (sheetList.Count > 0) 76 | { 77 | list.AddRange(sheetList); 78 | } 79 | } 80 | } 81 | 82 | return list; 83 | } 84 | 85 | private static List GetListFromWorksheet(ExcelWorksheet sheet, ImportExcelSetting importSetting,string excelName) where T : ExcelBase, new() 86 | { 87 | List list = new List(); 88 | if (sheet == null || sheet.Dimension == null) 89 | return list; 90 | 91 | Type entityType = typeof(T); 92 | List errorMessages = new List(); 93 | 94 | int maxColumnNum = sheet.Dimension.End.Column; 95 | int maxRowNum = sheet.Dimension.End.Row; 96 | 97 | var mergeList = sheet.MergedCells; 98 | 99 | for (int m = 1; m <= maxColumnNum; m++) 100 | { 101 | int cellRow = importSetting.ImportStyle.DataRowIndex - 1; 102 | var cell = sheet.Cells[cellRow, m]; 103 | if (cell.Merge) 104 | { 105 | var index = sheet.GetMergeCellId(cellRow, m); 106 | var range = sheet.MergedCells[index-1]?.Split(new char[1] {':' },StringSplitOptions.RemoveEmptyEntries); 107 | if (range != null && range.Length > 0) 108 | { 109 | cell = sheet.Cells[range[0]]; 110 | } 111 | } 112 | 113 | var importColumn = importSetting.ImportColumns.Where(o => o.Text == cell.Text?.Trim()).FirstOrDefault(); 114 | if (importColumn != null) 115 | { 116 | importColumn.ColumnIndex = m; 117 | } 118 | } 119 | 120 | importSetting.ImportColumns = importSetting.ImportColumns.Where(o => o.ColumnIndex > 0).ToList(); 121 | 122 | for (int n = importSetting.ImportStyle.DataRowIndex; n <= maxRowNum; n++) 123 | { 124 | var entity = Activator.CreateInstance(); 125 | //?? 126 | entity.ExcelName = excelName; 127 | entity.SheetName = sheet.Name; 128 | entity.RowIndex = n; 129 | 130 | foreach (var item in importSetting.ImportColumns) 131 | { 132 | entity.ColumnIndex = item.ColumnIndex; 133 | var property = entityType.GetProperty(item.Name); 134 | 135 | #region 数据校验 136 | try 137 | { 138 | //??sheet.Cells[n, item.ColumnIndex].Text 139 | var value = sheet.Cells[n, item.ColumnIndex].Value; 140 | if (value != null && value.ToString() != "") 141 | { 142 | if(value is string) 143 | { 144 | value = ((string)value).TrimStart(item.Prefix.ToArray()).TrimEnd(item.Suffix.ToArray()); 145 | } 146 | 147 | if (item.IsUseTempField) 148 | { 149 | var tempProperty = entityType.GetProperty(item.TempField); 150 | if (tempProperty != null) 151 | { 152 | tempProperty.SetValue(entity, value, null); 153 | } 154 | else 155 | { 156 | var tempField = entityType.GetField(item.TempField); 157 | if (tempField != null) 158 | { 159 | tempField.SetValue(entity, value); 160 | } 161 | } 162 | continue; 163 | } 164 | 165 | if (!string.IsNullOrEmpty(item.DataVerReg)) 166 | { 167 | var isMatch = Regex.IsMatch((string)value, item.DataVerReg); 168 | if (!isMatch && item.IsRegFailThrowException) 169 | { 170 | throw new ImportFormatException("正则表达式解析异常"); 171 | } 172 | } 173 | 174 | if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 175 | { 176 | if (value != null && value.ToString().Length > 0) 177 | { 178 | var tempValue = Convert.ChangeType(value, property.PropertyType.GetGenericArguments()[0]); 179 | property.SetValue(entity, tempValue, null); 180 | } 181 | } 182 | else 183 | { 184 | var tempValue = Convert.ChangeType(value, property.PropertyType); 185 | property.SetValue(entity, tempValue, null); 186 | } 187 | } 188 | 189 | } 190 | catch (ImportFormatException ex) 191 | { 192 | errorMessages.Add(string.Format("Excel{0}sheet:{1}第{2}行第{3}列【{4}】的值【{5}】不合法", entity.ExcelName, entity.SheetName, n, item.ColumnIndex, item.Text, sheet.Cells[n, item.ColumnIndex].Value)); 193 | } 194 | catch (Exception ex) 195 | { 196 | errorMessages.Add(string.Format("Excel{0}sheet:{1}第{2}行第{3}列【{4}】的值【{5}】转换异常", entity.ExcelName, entity.SheetName, n, item.ColumnIndex, item.Text, sheet.Cells[n, item.ColumnIndex].Value)); 197 | } 198 | #endregion 199 | } 200 | 201 | list.Add(entity); 202 | } 203 | 204 | if (errorMessages.Count > 0) 205 | { 206 | throw new ImportFormatException(errorMessages.ToArray()); 207 | } 208 | 209 | return list; 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/TemplateSetting/TemplateSettingRangeChart.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ExcelCake.NoIntrusive 8 | { 9 | [Serializable] 10 | internal class TemplateSettingRangeChart: TemplateSettingRange 11 | { 12 | public string Type { set; get; } 13 | 14 | //public EnumChartType ChartType { get; set; } 15 | 16 | /// 17 | /// 是否自定义宽、高,默认false。为true时使用ChartWidth、ChartHeight实现图表大小 18 | /// 19 | public bool IsCustomSize { get; set; } 20 | 21 | public int ChartWidth { get; set; } 22 | 23 | public int ChartHeight { get; set; } 24 | 25 | public string Title { get; set; } 26 | 27 | 28 | private TemplateSettingRangeChart() 29 | { 30 | 31 | } 32 | 33 | internal static TemplateSettingRangeChart Create(ExcelRangeBase cell) 34 | { 35 | var entity = new TemplateSettingRangeChart(); 36 | entity.Content = cell.Value?.ToString() ?? ""; 37 | entity.CurrentCell = cell; 38 | entity.AnalyseSetting(); 39 | return entity; 40 | } 41 | 42 | protected override void AnalyseSetting() 43 | { 44 | var cellValue = cell.Value?.ToString() ?? ""; 45 | var arry = cellValue.Split(new char[2] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries); 46 | if (arry.Length == 0) 47 | { 48 | continue; 49 | } 50 | foreach (var item in arry) 51 | { 52 | if (item.IndexOf(":") > -1 && item.IndexOf(";") > -1) 53 | { 54 | var settingItemArry = item.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); 55 | if (settingItemArry.Length == 0) 56 | { 57 | continue; 58 | } 59 | 60 | foreach (var settingItem in settingItemArry) 61 | { 62 | if (settingItem.ToUpper().IndexOf("TYPE") < 0) 63 | { 64 | continue; 65 | } 66 | 67 | var arrItem = settingItem.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries); 68 | if (arrItem.Length < 2) 69 | { 70 | continue; 71 | } 72 | 73 | var key = arrItem[0]; 74 | var value = arrItem[1]; 75 | 76 | 77 | switch (value.ToUpper()) 78 | { 79 | case "FREE": 80 | { 81 | var freeItem = TemplateSettingRangeFree.Create(cell); 82 | _FreeSettingList.Add(freeItem); 83 | } 84 | break; 85 | case "GRID": 86 | { 87 | var gridItem = TemplateSettingRangeGrid.Create(cell); 88 | _GridSettingList.Add(gridItem); 89 | } 90 | break; 91 | case "CHART": 92 | { 93 | var chartItem = TemplateSettingRangeChart.Create(cell); 94 | _ChartSettingList.Add(chartItem); 95 | } 96 | break; 97 | case "VALUE": 98 | { 99 | var fieldItem = TemplateSettingField.Create(cell); 100 | _FieldSettingList.Add(fieldItem); 101 | } 102 | break; 103 | } 104 | } 105 | 106 | 107 | #region free配置分解 108 | 109 | #endregion 110 | 111 | 112 | 113 | TemplateSettingRange setting = null; 114 | var type = ""; 115 | var chartSubType = ""; 116 | var title = ""; 117 | 118 | foreach (var arryItem in settingItemArry) 119 | { 120 | var settingItem = arryItem.Split(':'); 121 | if (settingItem.Length < 2) 122 | { 123 | continue; 124 | } 125 | var key = settingItem[0]; 126 | var value = settingItem[1]; 127 | if (string.IsNullOrEmpty(key)) 128 | { 129 | continue; 130 | } 131 | 132 | switch (key.ToUpper()) 133 | { 134 | case "TYPE": { type = value.ToUpper(); } break; 135 | case "SUBTYPE": { chartSubType = value.ToUpper(); } break; 136 | case "DATASOURCE": { setting.DataSource = value.ToUpper(); } break; 137 | case "ADDRESSLEFTTOP": { setting.AddressLeftTop = value.ToUpper(); } break; 138 | case "ADDRESSRIGHTBOTTOM": { setting.AddressRightBottom = value.ToUpper(); } break; 139 | case "FIELD": 140 | { 141 | var fieldSetting = new TemplateSettingField(); 142 | fieldSetting.Field = value.ToUpper(); 143 | fieldSetting.Content = "{" + item + "}"; 144 | fieldSetting.CurrentCell = cell; 145 | _FieldSettingList.Add(fieldSetting); 146 | } 147 | break; 148 | //case "TITLE": { title = value; }break; 149 | //case "WIDTH": {int.TryParse(value,out int width); setting.ChartWidth = width; } break; 150 | //case "HEIGHT": { int.TryParse(value, out int height); setting.ChartHeight = height; } break; 151 | //case "ISCUSTOMSIZE": { setting.IsCustomSize = (value == "1") ?true : false; }break; 152 | } 153 | } 154 | 155 | if (string.IsNullOrEmpty(type)) 156 | { 157 | continue; 158 | } 159 | else if (type == "GRID") 160 | { 161 | 162 | setting = new TemplateSettingRangeGrid(); 163 | setting.CurrentCell = cell; 164 | setting.Content = "{" + item + "}"; 165 | ExcelCommon.CalcRowCol(setting.AddressLeftTop, out int fromRow, out int fromCol); 166 | ExcelCommon.CalcRowCol(setting.AddressRightBottom, out int toRow, out int toCol); 167 | setting.FromRow = fromRow; 168 | setting.FromCol = fromCol; 169 | setting.ToRow = toRow; 170 | setting.ToCol = toCol; 171 | _GridSettingList.Add(setting); 172 | } 173 | else if (type == "FREE") 174 | { 175 | setting = new TemplateSettingRangeFree(); 176 | setting.CurrentCell = cell; 177 | setting.Content = "{" + item + "}"; 178 | ExcelCommon.CalcRowCol(setting.AddressLeftTop, out int fromRow, out int fromCol); 179 | ExcelCommon.CalcRowCol(setting.AddressRightBottom, out int toRow, out int toCol); 180 | setting.FromRow = fromRow; 181 | setting.FromCol = fromCol; 182 | setting.ToRow = toRow; 183 | setting.ToCol = toCol; 184 | _FreeSettingList.Add(setting); 185 | } 186 | else if (type == "CHART") 187 | { 188 | setting = new TemplateSettingRangeChart(); 189 | setting.CurrentCell = cell; 190 | setting.Content = "{" + item + "}"; 191 | ExcelCommon.CalcRowCol(setting.AddressLeftTop, out int fromRow, out int fromCol); 192 | ExcelCommon.CalcRowCol(setting.AddressRightBottom, out int toRow, out int toCol); 193 | setting.FromRow = fromRow; 194 | setting.FromCol = fromCol; 195 | setting.ToRow = toRow; 196 | setting.ToCol = toCol; 197 | _ChartSettingList.Add(setting); 198 | 199 | //if (string.IsNullOrEmpty(chartSubType)) 200 | //{ 201 | // setting.ChartType = EnumChartType.Chart; 202 | //} 203 | //else 204 | //{ 205 | // switch (chartSubType) 206 | // { 207 | // case "CHART": { setting.ChartType = EnumChartType.Chart; } break; 208 | // case "BARCHART": { setting.ChartType = EnumChartType.BarChart; } break; 209 | // case "BUBBLECHART": { setting.ChartType = EnumChartType.BubbleChart; } break; 210 | // case "DOUGHNUTCHART": { setting.ChartType = EnumChartType.DoughnutChart; } break; 211 | // case "LINECHART": { setting.ChartType = EnumChartType.LineChart; } break; 212 | // case "OFPIECHART": { setting.ChartType = EnumChartType.OfPieChart; } break; 213 | // case "PIECHART": { setting.ChartType = EnumChartType.PieChart; } break; 214 | // case "RADARCHART": { setting.ChartType = EnumChartType.RadarChart; } break; 215 | // case "SCATTERCHART": { setting.ChartType = EnumChartType.ScatterChart; } break; 216 | // case "SURFACECHART": { setting.ChartType = EnumChartType.SurfaceChart; } break; 217 | // default: { setting.ChartType = EnumChartType.Chart; } break; 218 | // } 219 | //} 220 | } 221 | else if (type == "VALUE") 222 | { 223 | _FieldSettingList.Add(setting); 224 | } 225 | 226 | } 227 | var cellValueStr = cell.Value?.ToString() ?? ""; 228 | cell.Value = cellValueStr.Replace("{" + item + "}", ""); 229 | } 230 | } 231 | 232 | internal override void Draw(ExcelWorksheet workSheet, ExcelObject dataSource) 233 | { 234 | throw new NotImplementedException(); 235 | } 236 | } 237 | 238 | internal enum EnumChartType 239 | { 240 | None = 0, 241 | Chart = 1, 242 | BarChart = 2, 243 | BubbleChart = 3, 244 | DoughnutChart = 4, 245 | LineChart = 5, 246 | OfPieChart = 6, 247 | PieChart = 7, 248 | RadarChart = 8, 249 | ScatterChart = 9, 250 | SurfaceChart = 10, 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /ExcelCake/NoIntrusive/ExcelTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using OfficeOpenXml; 5 | using System.IO; 6 | using System.Data; 7 | using System.Text.RegularExpressions; 8 | using System.Configuration; 9 | using OfficeOpenXml.Style; 10 | using System.Drawing; 11 | 12 | namespace ExcelCake.NoIntrusive 13 | { 14 | /// 15 | /// 自定义模板复杂格式导出(待重构) 16 | /// 17 | public class ExcelTemplate 18 | { 19 | private string _TemplateFile; 20 | private string _TemplateSheetName; 21 | 22 | private ExcelTemplate() 23 | { 24 | 25 | } 26 | 27 | public ExcelTemplate(string templateFilePath,string sheetName="Sheet1") 28 | { 29 | _TemplateFile = templateFilePath; 30 | _TemplateSheetName = sheetName; 31 | } 32 | 33 | /// 34 | /// 填充报表(待重构) 35 | /// 36 | /// 37 | /// 38 | /// 39 | public ExcelWorksheet FillSheetData(ExcelWorksheet workSheet,ExcelObject dataSource) 40 | { 41 | if (workSheet == null || dataSource == null) 42 | { 43 | return workSheet; 44 | } 45 | 46 | #region 分析配置 47 | TemplateSettingSheet sheetSetting = new TemplateSettingSheet(workSheet); 48 | #endregion 49 | 50 | #region 填充数据 51 | foreach (var item in sheetSetting.FreeSettingList) 52 | { 53 | if (string.IsNullOrEmpty(item.AddressLeftTop) || string.IsNullOrEmpty(item.AddressRightBottom)) 54 | { 55 | continue; 56 | } 57 | ExcelRange range = workSheet.Cells[item.AddressLeftTop+","+item.AddressRightBottom]; 58 | 59 | if (!dataSource.DataEntity.Keys.Contains(item.DataSource)) 60 | { 61 | continue; 62 | } 63 | var data = dataSource.DataEntity[item.DataSource]; 64 | 65 | foreach(var field in sheetSetting.FieldSettingList) 66 | { 67 | if (ExcelCommon.IsCellInRange(item.FromRow,item.FromCol,item.ToRow,item.ToCol,field.CurrentCell)) 68 | { 69 | var fieldName = field.Field; 70 | var value = field.CurrentCell.Value?.ToString() ?? ""; 71 | value = value.Replace(field.SettingString, ""); 72 | object fieldData = null; 73 | if (data.Keys.Contains(field.Field)) 74 | { 75 | fieldData = data[field.Field]; 76 | } 77 | field.CurrentCell.Value = value + fieldData; 78 | } 79 | } 80 | 81 | } 82 | 83 | List mergedList = new List(); 84 | foreach(var item in workSheet.MergedCells) 85 | { 86 | mergedList.Add(item.Replace(":",",")); 87 | } 88 | Dictionary regionAddDic = new Dictionary(); 89 | 90 | foreach (var item in sheetSetting.GridSettingList) 91 | { 92 | if (string.IsNullOrEmpty(item.AddressLeftTop) || string.IsNullOrEmpty(item.AddressRightBottom)) 93 | { 94 | continue; 95 | } 96 | ExcelRange range = workSheet.Cells[item.AddressLeftTop + "," + item.AddressRightBottom]; 97 | 98 | if (!dataSource.DataList.Keys.Contains(item.DataSource)) 99 | { 100 | continue; 101 | } 102 | var data = dataSource.DataList[item.DataSource]; 103 | 104 | //分析 105 | int offsetCount = 0; 106 | int addCount = 0; 107 | int sameCount = 0; 108 | int emptyCount = 0; 109 | 110 | if (data.Count > 0 && data.First().Value.Count() > 1) 111 | { 112 | addCount = data.First().Value.Count() - 1; 113 | } 114 | foreach (var addItem in regionAddDic) 115 | { 116 | if (addItem.Key.FromRow < item.FromRow&&addItem.Value>offsetCount) 117 | { 118 | offsetCount = addItem.Value; 119 | } 120 | else if(addItem.Key.FromRow == item.FromRow) 121 | { 122 | emptyCount = addItem.Value > addCount ? addItem.Value - addCount : 0; 123 | addCount = addItem.Value>addCount?0:addCount-addItem.Value; 124 | sameCount = addItem.Value > addCount ? 0 : addItem.Value; 125 | } 126 | } 127 | 128 | //动态添加行 129 | if (addCount>0) 130 | { 131 | workSheet.InsertRow(item.FromRow+offsetCount + 1, addCount); 132 | regionAddDic.Add(item, addCount + sameCount); 133 | } 134 | 135 | foreach (var field in sheetSetting.FieldSettingList) 136 | { 137 | if (ExcelCommon.IsCellInRange(item.FromRow, item.FromCol, item.ToRow, item.ToCol, field.CurrentCell)) 138 | { 139 | var fieldName = field.Field; 140 | List fieldDatas = new List(); 141 | 142 | if (data.Keys.Contains(field.Field)) 143 | { 144 | bool isFieldMerge = false; 145 | int fromRow = 1; 146 | int fromCol = 1; 147 | int toRow = 1; 148 | int toCol = 1; 149 | 150 | foreach (var merge in mergedList) 151 | { 152 | var arryMerge = merge.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); 153 | if (arryMerge.Length == 2) 154 | { 155 | var isMerge = ExcelCommon.IsCellInRange(arryMerge[0], arryMerge[1], field.CurrentCell); 156 | if (isMerge) 157 | { 158 | isFieldMerge = true; 159 | ExcelCommon.CalcRowCol(arryMerge[0], out fromRow, out fromCol); 160 | ExcelCommon.CalcRowCol(arryMerge[1], out toRow, out toCol); 161 | break; 162 | } 163 | } 164 | } 165 | 166 | fieldDatas = data[field.Field]; 167 | 168 | for (var i = 0; i < fieldDatas.Count; i++) 169 | { 170 | field.CurrentCell.Offset(i+ offsetCount, 0).Value = fieldDatas[i]; 171 | if (i == 0) 172 | { 173 | continue; 174 | } 175 | 176 | if (isFieldMerge) 177 | { 178 | var oldRange = workSheet.Cells[fromRow+ offsetCount, fromCol, toRow+ offsetCount, toCol]; 179 | var newRange = workSheet.Cells[fromRow+ offsetCount + i, fromCol, toRow+ offsetCount + i, toCol]; 180 | newRange.Merge = true; 181 | 182 | ExcelCommon.HandleCellStyle(oldRange, newRange); 183 | } 184 | else 185 | { 186 | var oldRange = field.CurrentCell.Offset(offsetCount, 0); 187 | var newRange = field.CurrentCell.Offset(i + offsetCount, 0); 188 | 189 | ExcelCommon.HandleCellStyle(oldRange, newRange); 190 | } 191 | } 192 | 193 | if (emptyCount > 0) 194 | { 195 | for (var i = 0; i < emptyCount; i++) 196 | { 197 | if (isFieldMerge) 198 | { 199 | var oldRange = workSheet.Cells[fromRow + offsetCount, fromCol, toRow + offsetCount, toCol]; 200 | var newRange = workSheet.Cells[fromRow + offsetCount + fieldDatas.Count + i, fromCol, toRow + offsetCount + fieldDatas.Count + i, toCol]; 201 | newRange.Merge = true; 202 | ExcelCommon.HandleCellStyle(oldRange, newRange); 203 | } 204 | else 205 | { 206 | var oldRange = field.CurrentCell.Offset(offsetCount, 0); 207 | var newRange = field.CurrentCell.Offset(i + offsetCount+ fieldDatas.Count, 0); 208 | ExcelCommon.HandleCellStyle(oldRange, newRange); 209 | } 210 | } 211 | } 212 | } 213 | } 214 | } 215 | } 216 | #endregion 217 | 218 | return workSheet; 219 | } 220 | 221 | /// 222 | /// 导出为byte[]数据 223 | /// 224 | /// 225 | /// 226 | /// 227 | /// 228 | public byte[] ExportToBytes(ExcelObject dataSource,string templatePath, string sheetName = "Sheet1") 229 | { 230 | byte[] excelBuffer = null; 231 | if (!File.Exists(templatePath)) 232 | { 233 | return excelBuffer; 234 | } 235 | 236 | using (ExcelPackage package = new ExcelPackage(new FileInfo(templatePath))) 237 | { 238 | //package.Workbook.Worksheets 239 | if (package.Workbook.Worksheets.Count < 1) 240 | { 241 | return excelBuffer; 242 | } 243 | ExcelPackage newPackage = new ExcelPackage(); 244 | newPackage.Workbook.Worksheets.Add(sheetName, package.Workbook.Worksheets[_TemplateSheetName]); 245 | var ws = newPackage.Workbook.Worksheets.First(); 246 | ws = FillSheetData(ws, dataSource); 247 | 248 | excelBuffer = newPackage.GetAsByteArray(); 249 | } 250 | return excelBuffer; 251 | } 252 | 253 | /// 254 | /// 导出为byte[]数据 255 | /// 256 | /// 257 | /// 258 | /// 259 | public byte[] ExportToBytes(object dataSource, string templatePath, string sheetName = "Sheet1") 260 | { 261 | return ExportToBytes(new ExcelObject(dataSource), templatePath, sheetName); 262 | } 263 | 264 | /// 265 | /// 导出为byte[]数据 266 | /// 267 | /// 268 | /// 269 | /// 270 | public byte[] ExportToBytes(DataSet dataSource,string templatePath,string sheetName = "Sheet1") 271 | { 272 | return ExportToBytes(new ExcelObject(dataSource), sheetName); 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExcelCake 2 | 3 | 基于 EPPlus 开发的 Excel(支持 excel 2007 及之后版本)通用导入导出类库(支持.net core)。 4 | 5 | [![](https://img.shields.io/badge/license-LGPL%20v3-blue.svg)](./LICENSE) 6 | [![](https://img.shields.io/badge/EPPlus-v4.5.3-brightgreen.svg)](https://github.com/JanKallman/EPPlus) 7 | ![](https://img.shields.io/badge/%E4%BD%9C%E8%80%85-winstonwxj-orange.svg) 8 | 9 | ## 分支说明 10 | - master:主分支,不接受合并。 11 | - Dev:开发分支,接收合并。仅支持.net core 3.1及以上。 12 | - OldVersion:旧版本分支(.net3.5、.net4.0、.net standard 2.0、.net standard 2.1版本代码)。有需要可以下载此分支。不承诺该分支的维护工作。 13 | 14 | ## 特性 15 | 16 | - 快速实现 Excel 导入导出功能 17 | - ~~老旧项目(.net 3.5、.net 4.0、.net standard 2.0、.net standard 2.1)支持~~(旧版本代码移步至OldVersion分支) 18 | - 跨平台支持(.net core 3.1及以上) 19 | - 多种实现机制:1.基于特性实现的导入导出(侵入式) 2.基于模板实现的导入导出(非侵入式) 3.动态读取配置实现导入导出 20 | 21 | ## ExcelCake 源码结构 22 | 23 | ``` 24 | |--ExcelCake 源码 25 | |----Intrusive 侵入式部分 26 | |----NoIntrusive 非侵入式部分 27 | |----Dynamic 动态配置部分 28 | |--ExcelCake.Example Demo 29 | |--ExcelCake.Test 单元测试 30 | ``` 31 | 32 | ## **作者相关** 33 | 34 | github: https://github.com/winstonwxj 35 | 36 | gitee: (不再维护) 37 | 38 | ## 路线图 39 | 40 | - 基于特性数据导出(已实现) 41 | - 基于特性数据导入(已实现) 42 | - 基于特性图片导出 43 | - 基于特性图表导出 44 | - 基于模板表格导出(已实现) 45 | - 基于模板表格导入 46 | - 基于模板图片导出 47 | - 基于模板图表导出 48 | - 基于动态配置数据导出 49 | - 基于动态配置数据导入 50 | - 基于动态配置图片导出 51 | - 基于动态配置图表导出 52 | - 使用其他office open xml实现替代EPPlus 53 | 54 | ## 模板语法 55 | ### (新版语法) 56 | **语法可用的最小粒度为配置项,每个配置项使用大括号包裹,各项之间以分号”;”分隔,项和值之间以冒号”:”分隔,忽略大小写。地址配置项为Address时,值以,分隔。** 57 | - Data:数据源,该项值为数据源中的成员变量,类型必须为属性(含get,set),不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性,该项为空。用于Free配置类型(自由格式配置) 58 | - List:数据源,该项值为数据源中的成员变量,类型必须为属性(含get,set),不支持字段,Type不为Value时可用。如果Value配置字段为数据源集合单个实体的直接属性,该项为空。用于Grid配置类型(表格格式配置)该项值为数据源中的成员变量,类型必须为属性(含get,set),不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性,该项为空。 59 | - @:填充字段名称 60 | LT:区域左上角单元格坐标,Type不为Value时可用 61 | RB:区域右下角单元格坐标,Type不为Value时可用 62 | Address:指定区域地址,以,号分隔的“区域左上角单元格坐标”和“区域右下角单元格坐标” 63 | 64 | **配置示例:** 65 | 1. 自由格式 66 | {Data:具体对象;LT:区域左上坐标;RB:区域右下坐标} 67 | 或{Data:具体对象;Address:区域左上坐标,区域右下坐标} 68 | 2. 表格格式 69 | {List:具体对象(集合类型,不支持数组);LT:区域左上坐标;RB:区域右下坐标} 70 | 或{List:具体对象(集合类型,不支持数组);Address:区域左上坐标,区域右下坐标} 71 | 3. 具体填充字段名称 72 | {@字段名称} 73 | 74 | ### (旧版语法) 75 | **语法可用的最小粒度为配置项,每个配置项使用大括号包裹,各项之间以分号”;”分隔,项和值之间以冒号”:”分隔,忽略大小写。** 76 | - Type:配置类型,包括Free(自由格式配置),Grid(表格格式配置),Value(填充字段配置) 77 | - DataSource:数据源,该项值为数据源中的成员变量,类型必须为属性(含get,set),不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性,该项为空。 78 | - AddressLeftTop:区域左上角单元格坐标,Type不为Value时可用 79 | - AddressRightBottom:区域右下角单元格坐标,Type不为Value时可用 80 | - Field:字段名称,Type为Value时可用 81 | 82 | **配置示例:** 83 | 1. 自由格式 84 | {Type:Free;DataSource:具体对象;AddressLeftTop:区域左上坐标;AddressRightBottom:区域右下坐标} 85 | 2. 表格格式 86 | {Type:Grid;DataSource:具体对象(集合类型,不支持数组);AddressLeftTop:区域左上坐标;AddressRightBottom:区域右下坐标} 87 | 3. 具体填充字段名称 88 | {Type:Value;Field:字段名称} 89 | 90 | 91 | ## 示例 92 | 93 | ### 基于特性部分 94 | #### 实体类定义 95 | 96 | ```C# 97 | [ExportEntity(EnumColor.LightGray,"用户信息")] 98 | [ImportEntity(titleRowIndex:1,headRowIndex:2,dataRowIndex:4)] 99 | public class UserInfo: ExcelBase 100 | { 101 | [Export(name:"编号", index:1,prefix:"ID:")] 102 | [Import(name:"编号",prefix:"ID:")] 103 | public int ID { set; get; } 104 | 105 | [Export("姓名", 2)] 106 | [Import("姓名")] 107 | public string Name { set; get; } 108 | 109 | [Export("性别", 3)] 110 | [Import("性别")] 111 | public string Sex { set; get; } 112 | 113 | [Export(name:"年龄", index:4,suffix:"岁")] 114 | [Import(name:"年龄",suffix:"岁",dataVerReg: @"^[1-9]\d*$", isRegFailThrowException:false)] 115 | public int Age { set; get; } 116 | 117 | [ExportMerge("联系方式")] 118 | [Export("电子邮件", 5)] 119 | [Import("电子邮件")] 120 | public string Email { set; get; } 121 | 122 | [ExportMerge("联系方式")] 123 | [Export("手机", 6)] 124 | [Import("手机")] 125 | public string TelPhone { set; get; } 126 | 127 | public override string ToString() 128 | { 129 | return string.Format($"ID:{ID},Name:{Name},Sex:{Sex},Age:{Age},Email:{Email},TelPhone:{TelPhone}"); 130 | } 131 | } 132 | 133 | [ExportEntity("账号信息")] 134 | public class AccountInfo:ExcelBase 135 | { 136 | [Export("编号", 1)] 137 | public int ID { set; get; } 138 | 139 | [Export("昵称", 2)] 140 | public string Nickname { set; get; } 141 | 142 | [Export("密码", 3)] 143 | public string Password { set; get; } 144 | 145 | [Export("旧密码", 4)] 146 | public string OldPassword { set; get; } 147 | 148 | [Export("状态", 5)] 149 | public int AccountStatus { set; get; } 150 | } 151 | ``` 152 | 153 | #### 基于特性导出 154 | ```C# 155 | private static void IntrusiveExport() 156 | { 157 | List list = new List(); 158 | string[] sex = new string[] { "男", "女" }; 159 | Random random = new Random(); 160 | for (var i = 0; i < 100; i++) 161 | { 162 | list.Add(new UserInfo() 163 | { 164 | ID = i + 1, 165 | Name = "Test" + (i + 1), 166 | Sex = sex[random.Next(2)], 167 | Age = random.Next(20, 50), 168 | Email = "test" + (i + 1) + "@163.com", 169 | TelPhone = "1399291" + random.Next(1000, 9999) 170 | }); 171 | } 172 | var temp = list.ExportToExcelBytes(); //导出为byte[] 173 | 174 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 175 | if (!Directory.Exists(path)) 176 | { 177 | Directory.CreateDirectory(path); 178 | } 179 | var exportTitle = "导出文件"; 180 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 181 | FileInfo file = new FileInfo(filePath); 182 | File.WriteAllBytes(file.FullName, temp); 183 | Console.WriteLine("IntrusiveExport导出完成!"); 184 | } 185 | ``` 186 | ![avatar](./pics/pic1.PNG) 187 | 188 | #### 基于特性多sheet多类型导出 189 | ```C# 190 | private static void IntrusiveMultiSheetExport() 191 | { 192 | Dictionary> excelSheets = new Dictionary>(); 193 | 194 | List list = new List(); 195 | List list2 = new List(); 196 | string[] sex = new string[] { "男", "女" }; 197 | 198 | Random random = new Random(); 199 | for (var i = 0; i < 10000; i++) 200 | { 201 | list.Add(new UserInfo() 202 | { 203 | ID = i + 1, 204 | Name = "Test" + (i + 1), 205 | Sex = sex[random.Next(2)], 206 | Age = random.Next(20, 50), 207 | Email = "testafsdgfashgawefqwefasdfwefqwefasdggfaw" + (i + 1) + "@163.com", 208 | TelPhone = "1399291" + random.Next(1000, 9999) 209 | }); 210 | list2.Add(new AccountInfo() 211 | { 212 | ID = i + 1, 213 | Nickname = "nick" + (i + 1), 214 | Password = random.Next(111111, 999999).ToString(), 215 | OldPassword = random.Next(111111, 999999).ToString(), 216 | AccountStatus = random.Next(2) 217 | }); 218 | } 219 | excelSheets.Add("sheet1", list); 220 | excelSheets.Add("sheet2", list2); 221 | 222 | 223 | var temp = excelSheets.ExportMultiToBytes(); //导出为byte[] 224 | 225 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 226 | if (!Directory.Exists(path)) 227 | { 228 | Directory.CreateDirectory(path); 229 | } 230 | var exportTitle = "导出文件"; 231 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 232 | FileInfo file = new FileInfo(filePath); 233 | File.WriteAllBytes(file.FullName, temp); 234 | Console.WriteLine("IntrusiveMultiSheetExport导出完成!"); 235 | } 236 | ``` 237 | ![avatar](./pics/pic3.PNG) 238 | ![avatar](./pics/pic4.PNG) 239 | 240 | #### 导入Excel文件结构 241 | ![avatar](./pics/pic7.PNG) 242 | 243 | #### 基于特性导入 244 | ```C# 245 | private static void IntrusiveImport() 246 | { 247 | var list = ExcelHelper.GetList(@"C:\Users\winstonwxj\Desktop\导入文件测试.xlsx"); 248 | foreach(var item in list) 249 | { 250 | Console.WriteLine(item); 251 | } 252 | Console.WriteLine("导入完成!"); 253 | } 254 | ``` 255 | ![avatar](./pics/pic5.PNG) 256 | 257 | ### 基于模板部分 258 | #### 模板绘制 259 | (旧版语法)![avatar](./pics/pic6.PNG) 260 | (新版语法)![avatar](./pics/pic6new.PNG) 261 | 262 | #### 基于模板导出 263 | ```C# 264 | private static void NoIntrusiveExport() 265 | { 266 | var reportInfo = new GradeReportInfo(); 267 | var exportTitle = "2018学年期中考试各班成绩汇总"; 268 | reportInfo.ReportTitle = exportTitle; 269 | var templateFileName = "复杂格式测试模板.xlsx"; 270 | 271 | #region 构造数据 272 | var list1 = new List(); 273 | list1.Add(new ClassInfo() 274 | { 275 | ClassName = "班级1", 276 | PassCountSubject1 = 20, 277 | PassCountSubject2 = 15, 278 | PassCountSubject3 = 10, 279 | PassCountSubject4 = 13, 280 | PassCountSubject5 = 25 281 | }); 282 | list1.Add(new ClassInfo() 283 | { 284 | ClassName = "班级2", 285 | PassCountSubject1 = 19, 286 | PassCountSubject2 = 20, 287 | PassCountSubject3 = 17, 288 | PassCountSubject4 = 11, 289 | PassCountSubject5 = 19 290 | }); 291 | list1.Add(new ClassInfo() 292 | { 293 | ClassName = "班级3", 294 | PassCountSubject1 = 17, 295 | PassCountSubject2 = 23, 296 | PassCountSubject3 = 12, 297 | PassCountSubject4 = 16, 298 | PassCountSubject5 = 21 299 | }); 300 | list1.Add(new ClassInfo() 301 | { 302 | ClassName = "班级4", 303 | PassCountSubject1 = 23, 304 | PassCountSubject2 = 17, 305 | PassCountSubject3 = 16, 306 | PassCountSubject4 = 14, 307 | PassCountSubject5 = 22 308 | }); 309 | list1.Add(new ClassInfo() 310 | { 311 | ClassName = "班级5", 312 | PassCountSubject1 = 23, 313 | PassCountSubject2 = 17, 314 | PassCountSubject3 = 16, 315 | PassCountSubject4 = 14, 316 | PassCountSubject5 = 22 317 | }); 318 | var list2 = new List(); 319 | list2.Add(new ClassInfo() 320 | { 321 | ClassName = "班级1", 322 | ScoreAvgSubject1 = 81.25, 323 | ScoreAvgSubject2 = 65.75, 324 | ScoreAvgSubject3 = 79.05, 325 | ScoreAvgSubject4 = 59.15, 326 | ScoreAvgSubject5 = 83.05 327 | }); 328 | list2.Add(new ClassInfo() 329 | { 330 | ClassName = "班级2", 331 | ScoreAvgSubject1 = 79.25, 332 | ScoreAvgSubject2 = 63.75, 333 | ScoreAvgSubject3 = 71.05, 334 | ScoreAvgSubject4 = 62.15, 335 | ScoreAvgSubject5 = 85 336 | }); 337 | list2.Add(new ClassInfo() 338 | { 339 | ClassName = "班级3", 340 | ScoreAvgSubject1 = 71.5, 341 | ScoreAvgSubject2 = 63.25, 342 | ScoreAvgSubject3 = 75.25, 343 | ScoreAvgSubject4 = 61.25, 344 | ScoreAvgSubject5 = 80.05 345 | }); 346 | list2.Add(new ClassInfo() 347 | { 348 | ClassName = "班级4", 349 | ScoreAvgSubject1 = 84.5, 350 | ScoreAvgSubject2 = 61.25, 351 | ScoreAvgSubject3 = 75.25, 352 | ScoreAvgSubject4 = 57.35, 353 | ScoreAvgSubject5 = 81.5 354 | }); 355 | var list3 = new List(); 356 | list3.Add(new ClassInfo() 357 | { 358 | ClassName = "班级1", 359 | ScoreTotalMax = 432, 360 | ScoreTotalAvg = 315.25, 361 | ScoreTotalPassRate = 47.25 362 | }); 363 | list3.Add(new ClassInfo() 364 | { 365 | ClassName = "班级2", 366 | ScoreTotalMax = 466.5, 367 | ScoreTotalAvg = 330.75, 368 | ScoreTotalPassRate = 44.75 369 | }); 370 | list3.Add(new ClassInfo() 371 | { 372 | ClassName = "班级3", 373 | ScoreTotalMax = 422, 374 | ScoreTotalAvg = 345.25, 375 | ScoreTotalPassRate = 51.05 376 | }); 377 | list3.Add(new ClassInfo() 378 | { 379 | ClassName = "班级4", 380 | ScoreTotalMax = 444, 381 | ScoreTotalAvg = 335.25, 382 | ScoreTotalPassRate = 46.15 383 | }); 384 | #endregion 385 | 386 | reportInfo.List1 = list1; 387 | reportInfo.List2 = list2; 388 | reportInfo.List3 = list3; 389 | 390 | ExcelTemplate customTemplate = new ExcelTemplate(templateFileName); 391 | var byteInfo = customTemplate.ExportToBytes(reportInfo, "Template/复杂格式测试模板.xlsx"); 392 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 393 | if (!Directory.Exists(path)) 394 | { 395 | Directory.CreateDirectory(path); 396 | } 397 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 398 | FileInfo file = new FileInfo(filePath); 399 | File.WriteAllBytes(file.FullName, byteInfo); 400 | Console.WriteLine("NoIntrusiveExport导出完成!"); 401 | } 402 | ``` 403 | ![avatar](./pics/pic2.PNG) 404 | 405 | ## 文档 406 | -------------------------------------------------------------------------------- /ExcelCake.Example/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using ExcelCake.Intrusive; 6 | using ExcelCake.NoIntrusive; 7 | using OfficeOpenXml.Drawing.Chart; 8 | using OfficeOpenXml.Drawing; 9 | using OfficeOpenXml.Style; 10 | using OfficeOpenXml; 11 | 12 | namespace ExcelCake.Example.Core 13 | { 14 | class Program 15 | { 16 | static void Main(string[] args) 17 | { 18 | //IntrusiveExport(); 19 | //IntrusiveMultiSheetExport(); 20 | NoIntrusiveExport(); 21 | //IntrusiveImport(); 22 | //DrawTest(); 23 | Console.ReadKey(); 24 | } 25 | 26 | private static void IntrusiveExport() 27 | { 28 | List list = new List(); 29 | string[] sex = new string[] { "男", "女" }; 30 | Random random = new Random(); 31 | for (var i = 0; i < 100; i++) 32 | { 33 | list.Add(new UserInfo() 34 | { 35 | ID = i + 1, 36 | Name = "Test" + (i + 1), 37 | Sex = sex[random.Next(2)], 38 | Age = random.Next(20, 50), 39 | Email = "test" + (i + 1) + "@163.com", 40 | TelPhone = "1399291" + random.Next(1000,9999) 41 | }); 42 | } 43 | var temp = list.ExportToExcelBytes(); //导出为byte[] 44 | 45 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 46 | if (!Directory.Exists(path)) 47 | { 48 | Directory.CreateDirectory(path); 49 | } 50 | var exportTitle = "导出文件"; 51 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 52 | FileInfo file = new FileInfo(filePath); 53 | File.WriteAllBytes(file.FullName, temp); 54 | Console.WriteLine("IntrusiveExport导出完成!"); 55 | } 56 | 57 | private static void IntrusiveMultiSheetExport() 58 | { 59 | Dictionary> excelSheets = new Dictionary>(); 60 | 61 | List list = new List(); 62 | List list2 = new List(); 63 | string[] sex = new string[] { "男", "女" }; 64 | 65 | Random random = new Random(); 66 | for (var i = 0; i < 100; i++) 67 | { 68 | list.Add(new UserInfo() 69 | { 70 | ID = i + 1, 71 | Name = "Test" + (i + 1), 72 | Sex = sex[random.Next(2)], 73 | Age = random.Next(20, 50), 74 | Email = "testafsdgfashgawefqwefasdfwefqwefasdggfaw" + (i + 1) + "@163.com", 75 | TelPhone = "1399291" + random.Next(1000, 9999) 76 | }); 77 | list2.Add(new AccountInfo() 78 | { 79 | ID = i + 1, 80 | Nickname = "nick" + (i + 1), 81 | Password = random.Next(111111, 999999).ToString(), 82 | OldPassword = random.Next(111111, 999999).ToString(), 83 | AccountStatus = random.Next(2) 84 | }); 85 | } 86 | excelSheets.Add("sheet1", list); 87 | excelSheets.Add("sheet2", list2); 88 | 89 | 90 | var temp = excelSheets.ExportMultiToBytes(); //导出为byte[] 91 | 92 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 93 | if (!Directory.Exists(path)) 94 | { 95 | Directory.CreateDirectory(path); 96 | } 97 | var exportTitle = "导出文件"; 98 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 99 | FileInfo file = new FileInfo(filePath); 100 | File.WriteAllBytes(file.FullName, temp); 101 | Console.WriteLine("IntrusiveMultiSheetExport导出完成!"); 102 | } 103 | 104 | private static void NoIntrusiveExport() 105 | { 106 | var reportInfo = new GradeReportInfo(); 107 | var exportTitle = "2018学年期中考试各班成绩汇总"; 108 | reportInfo.ReportTitle = exportTitle; 109 | //var templateFileName = "复杂格式测试模板.xlsx"; 110 | var templateFileName = "复杂格式测试模板(新语法).xlsx"; 111 | 112 | #region 构造数据 113 | var list1 = new List(); 114 | list1.Add(new ClassInfo() 115 | { 116 | ClassName = "班级1", 117 | PassCountSubject1 = 20, 118 | PassCountSubject2 = 15, 119 | PassCountSubject3 = 10, 120 | PassCountSubject4 = 13, 121 | PassCountSubject5 = 25 122 | }); 123 | list1.Add(new ClassInfo() 124 | { 125 | ClassName = "班级2", 126 | PassCountSubject1 = 19, 127 | PassCountSubject2 = 20, 128 | PassCountSubject3 = 17, 129 | PassCountSubject4 = 11, 130 | PassCountSubject5 = 19 131 | }); 132 | list1.Add(new ClassInfo() 133 | { 134 | ClassName = "班级3", 135 | PassCountSubject1 = 17, 136 | PassCountSubject2 = 23, 137 | PassCountSubject3 = 12, 138 | PassCountSubject4 = 16, 139 | PassCountSubject5 = 21 140 | }); 141 | list1.Add(new ClassInfo() 142 | { 143 | ClassName = "班级4", 144 | PassCountSubject1 = 23, 145 | PassCountSubject2 = 17, 146 | PassCountSubject3 = 16, 147 | PassCountSubject4 = 14, 148 | PassCountSubject5 = 22 149 | }); 150 | list1.Add(new ClassInfo() 151 | { 152 | ClassName = "班级5", 153 | PassCountSubject1 = 23, 154 | PassCountSubject2 = 17, 155 | PassCountSubject3 = 16, 156 | PassCountSubject4 = 14, 157 | PassCountSubject5 = 22 158 | }); 159 | var list2 = new List(); 160 | list2.Add(new ClassInfo() 161 | { 162 | ClassName = "班级1", 163 | ScoreAvgSubject1 = 81.25, 164 | ScoreAvgSubject2 = 65.75, 165 | ScoreAvgSubject3 = 79.05, 166 | ScoreAvgSubject4 = 59.15, 167 | ScoreAvgSubject5 = 83.05 168 | }); 169 | list2.Add(new ClassInfo() 170 | { 171 | ClassName = "班级2", 172 | ScoreAvgSubject1 = 79.25, 173 | ScoreAvgSubject2 = 63.75, 174 | ScoreAvgSubject3 = 71.05, 175 | ScoreAvgSubject4 = 62.15, 176 | ScoreAvgSubject5 = 85 177 | }); 178 | list2.Add(new ClassInfo() 179 | { 180 | ClassName = "班级3", 181 | ScoreAvgSubject1 = 71.5, 182 | ScoreAvgSubject2 = 63.25, 183 | ScoreAvgSubject3 = 75.25, 184 | ScoreAvgSubject4 = 61.25, 185 | ScoreAvgSubject5 = 80.05 186 | }); 187 | list2.Add(new ClassInfo() 188 | { 189 | ClassName = "班级4", 190 | ScoreAvgSubject1 = 84.5, 191 | ScoreAvgSubject2 = 61.25, 192 | ScoreAvgSubject3 = 75.25, 193 | ScoreAvgSubject4 = 57.35, 194 | ScoreAvgSubject5 = 81.5 195 | }); 196 | var list3 = new List(); 197 | list3.Add(new ClassInfo() 198 | { 199 | ClassName = "班级1", 200 | ScoreTotalMax = 432, 201 | ScoreTotalAvg = 315.25, 202 | ScoreTotalPassRate = 47.25 203 | }); 204 | list3.Add(new ClassInfo() 205 | { 206 | ClassName = "班级2", 207 | ScoreTotalMax = 466.5, 208 | ScoreTotalAvg = 330.75, 209 | ScoreTotalPassRate = 44.75 210 | }); 211 | list3.Add(new ClassInfo() 212 | { 213 | ClassName = "班级3", 214 | ScoreTotalMax = 422, 215 | ScoreTotalAvg = 345.25, 216 | ScoreTotalPassRate = 51.05 217 | }); 218 | list3.Add(new ClassInfo() 219 | { 220 | ClassName = "班级4", 221 | ScoreTotalMax = 444, 222 | ScoreTotalAvg = 335.25, 223 | ScoreTotalPassRate = 46.15 224 | }); 225 | #endregion 226 | 227 | reportInfo.List1 = list1; 228 | reportInfo.List2 = list2; 229 | reportInfo.List3 = list3; 230 | 231 | ExcelTemplate customTemplate = new ExcelTemplate(templateFileName); 232 | var byteInfo = customTemplate.ExportToBytes(reportInfo, "Template/"+ templateFileName); 233 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Export"); 234 | if (!Directory.Exists(path)) 235 | { 236 | Directory.CreateDirectory(path); 237 | } 238 | var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + ".xlsx"); 239 | FileInfo file = new FileInfo(filePath); 240 | File.WriteAllBytes(file.FullName, byteInfo); 241 | Console.WriteLine("NoIntrusiveExport导出完成!"); 242 | } 243 | 244 | private static void IntrusiveImport() 245 | { 246 | var list = ExcelHelper.GetList(@"C:\Users\winstonwxj\Desktop\导入文件测试.xlsx"); 247 | foreach(var item in list) 248 | { 249 | Console.WriteLine(item); 250 | } 251 | Console.WriteLine("导入完成!"); 252 | } 253 | 254 | static void DrawTest() 255 | { 256 | //ExcelBarChart 257 | //ExcelBubbleChart 258 | //ExcelChart 259 | //ExcelDoughnutChart 260 | //ExcelLineChart 261 | //ExcelOfPieChart 262 | //ExcelPieChart 263 | //ExcelRadarChart 264 | //ExcelScatterChart 265 | //ExcelSurfaceChart 266 | 267 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.xlsx"); 268 | if (File.Exists(path)) 269 | { 270 | File.Delete(path); 271 | } 272 | using (ExcelPackage package = new ExcelPackage()) 273 | { 274 | var hideWorksheet = package.Workbook.Worksheets.Add("dic"); 275 | hideWorksheet.Hidden = eWorkSheetHidden.VeryHidden; 276 | hideWorksheet.Cells.Style.WrapText = true; 277 | hideWorksheet.Cells[1, 1].Value = "名称"; 278 | hideWorksheet.Cells[1, 2].Value = "价格"; 279 | hideWorksheet.Cells[1, 3].Value = "销量"; 280 | 281 | hideWorksheet.Cells[2, 1].Value = "大米"; 282 | hideWorksheet.Cells[2, 2].Value = 56; 283 | hideWorksheet.Cells[2, 3].Value = 100; 284 | 285 | hideWorksheet.Cells[3, 1].Value = "玉米"; 286 | hideWorksheet.Cells[3, 2].Value = 45; 287 | hideWorksheet.Cells[3, 3].Value = 150; 288 | 289 | hideWorksheet.Cells[4, 1].Value = "小米"; 290 | hideWorksheet.Cells[4, 2].Value = 38; 291 | hideWorksheet.Cells[4, 3].Value = 130; 292 | 293 | hideWorksheet.Cells[5, 1].Value = "糯米"; 294 | hideWorksheet.Cells[5, 2].Value = 22; 295 | hideWorksheet.Cells[5, 3].Value = 200; 296 | 297 | using (ExcelRange range = hideWorksheet.Cells[1, 1, 5, 3]) 298 | { 299 | range.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 300 | range.Style.VerticalAlignment = ExcelVerticalAlignment.Center; 301 | } 302 | 303 | using (ExcelRange range = hideWorksheet.Cells[1, 1, 1, 3]) 304 | { 305 | range.Style.Font.Bold = true; 306 | range.Style.Font.Color.SetColor(Color.White); 307 | range.Style.Font.Name = "微软雅黑"; 308 | range.Style.Font.Size = 12; 309 | range.Style.Fill.PatternType = ExcelFillStyle.Solid; 310 | range.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(128, 128, 128)); 311 | } 312 | 313 | hideWorksheet.Cells[1, 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 314 | hideWorksheet.Cells[1, 2].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 315 | hideWorksheet.Cells[1, 3].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 316 | 317 | hideWorksheet.Cells[2, 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 318 | hideWorksheet.Cells[2, 2].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 319 | hideWorksheet.Cells[2, 3].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 320 | 321 | hideWorksheet.Cells[3, 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 322 | hideWorksheet.Cells[3, 2].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 323 | hideWorksheet.Cells[3, 3].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 324 | 325 | hideWorksheet.Cells[4, 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 326 | hideWorksheet.Cells[4, 2].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 327 | hideWorksheet.Cells[4, 3].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 328 | 329 | hideWorksheet.Cells[5, 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 330 | hideWorksheet.Cells[5, 2].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 331 | hideWorksheet.Cells[5, 3].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.FromArgb(191, 191, 191)); 332 | 333 | ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("test"); 334 | 335 | worksheet.Cells.Style.WrapText = true; 336 | worksheet.View.ShowGridLines = false;//去掉sheet的网格线 337 | 338 | //ExcelChart chart = worksheet.Drawings.AddChart("chart", eChartType.ColumnClustered); 339 | ExcelChart chart = worksheet.Drawings.AddChart("chart", eChartType.ConeCol); 340 | 341 | //ExcelChartSerie serie = chart.Series.Add(worksheet.Cells[2, 3, 5, 3], worksheet.Cells[2, 1, 5, 1]); 342 | //serie.HeaderAddress = worksheet.Cells[1, 3]; 343 | 344 | ExcelChartSerie serie = chart.Series.Add("dic!$C$1:$C$5", "dic!$A$1:$A$5"); 345 | serie.HeaderAddress = hideWorksheet.Cells[1, 3]; 346 | 347 | chart.SetPosition(150, 10); 348 | chart.SetSize(500, 300); 349 | chart.Title.Text = "销量走势"; 350 | chart.Title.Font.Color = Color.FromArgb(89, 89, 89); 351 | chart.Title.Font.Size = 15; 352 | chart.Title.Font.Bold = true; 353 | chart.Style = eChartStyle.Style15; 354 | chart.Legend.Border.LineStyle = eLineStyle.Solid; 355 | chart.Legend.Border.Fill.Color = Color.FromArgb(217, 217, 217); 356 | 357 | package.SaveAs(new FileInfo(path)); 358 | } 359 | 360 | } 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Enum/EnumColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ExcelCake.Intrusive 7 | { 8 | public enum EnumColor 9 | { 10 | // 11 | // 摘要: 12 | // Gets a system-defined color that has an ARGB value of #FF66CDAA. 13 | MediumAquamarine, 14 | // 15 | // 摘要: 16 | // Gets a system-defined color that has an ARGB value of #FF0000CD. 17 | MediumBlue, 18 | // 19 | // 摘要: 20 | // Gets a system-defined color that has an ARGB value of #FFBA55D3. 21 | MediumOrchid, 22 | // 23 | // 摘要: 24 | // Gets a system-defined color that has an ARGB value of #FF9370DB. 25 | MediumPurple, 26 | // 27 | // 摘要: 28 | // Gets a system-defined color that has an ARGB value of #FF3CB371. 29 | MediumSeaGreen, 30 | // 31 | // 摘要: 32 | // Gets a system-defined color that has an ARGB value of #FF7B68EE. 33 | MediumSlateBlue, 34 | // 35 | // 摘要: 36 | // Gets a system-defined color that has an ARGB value of #FF00FA9A. 37 | MediumSpringGreen, 38 | // 39 | // 摘要: 40 | // Gets a system-defined color that has an ARGB value of #FF800000. 41 | Maroon, 42 | // 43 | // 摘要: 44 | // Gets a system-defined color that has an ARGB value of #FF48D1CC. 45 | MediumTurquoise, 46 | // 47 | // 摘要: 48 | // Gets a system-defined color that has an ARGB value of #FF191970. 49 | MidnightBlue, 50 | // 51 | // 摘要: 52 | // Gets a system-defined color that has an ARGB value of #FFF5FFFA. 53 | MintCream, 54 | // 55 | // 摘要: 56 | // Gets a system-defined color that has an ARGB value of #FFFFE4E1. 57 | MistyRose, 58 | // 59 | // 摘要: 60 | // Gets a system-defined color that has an ARGB value of #FFFFE4B5. 61 | Moccasin, 62 | // 63 | // 摘要: 64 | // Gets a system-defined color that has an ARGB value of #FFFFDEAD. 65 | NavajoWhite, 66 | // 67 | // 摘要: 68 | // Gets a system-defined color that has an ARGB value of #FF000080. 69 | Navy, 70 | // 71 | // 摘要: 72 | // Gets a system-defined color that has an ARGB value of #FFFDF5E6. 73 | OldLace, 74 | // 75 | // 摘要: 76 | // Gets a system-defined color that has an ARGB value of #FFC71585. 77 | MediumVioletRed, 78 | // 79 | // 摘要: 80 | // Gets a system-defined color that has an ARGB value of #FFFF00FF. 81 | Magenta, 82 | // 83 | // 摘要: 84 | // Gets a system-defined color that has an ARGB value of #FFFAF0E6. 85 | Linen, 86 | // 87 | // 摘要: 88 | // Gets a system-defined color that has an ARGB value of #FF32CD32. 89 | LimeGreen, 90 | // 91 | // 摘要: 92 | // Gets a system-defined color that has an ARGB value of #FFFFF0F5. 93 | LavenderBlush, 94 | // 95 | // 摘要: 96 | // Gets a system-defined color that has an ARGB value of #FF7CFC00. 97 | LawnGreen, 98 | // 99 | // 摘要: 100 | // Gets a system-defined color that has an ARGB value of #FFFFFACD. 101 | LemonChiffon, 102 | // 103 | // 摘要: 104 | // Gets a system-defined color that has an ARGB value of #FFADD8E6. 105 | LightBlue, 106 | // 107 | // 摘要: 108 | // Gets a system-defined color that has an ARGB value of #FFF08080. 109 | LightCoral, 110 | // 111 | // 摘要: 112 | // Gets a system-defined color that has an ARGB value of #FFE0FFFF. 113 | LightCyan, 114 | // 115 | // 摘要: 116 | // Gets a system-defined color that has an ARGB value of #FFFAFAD2. 117 | LightGoldenrodYellow, 118 | // 119 | // 摘要: 120 | // Gets a system-defined color that has an ARGB value of #FFD3D3D3. 121 | LightGray, 122 | // 123 | // 摘要: 124 | // Gets a system-defined color that has an ARGB value of #FF90EE90. 125 | LightGreen, 126 | // 127 | // 摘要: 128 | // Gets a system-defined color that has an ARGB value of #FFFFB6C1. 129 | LightPink, 130 | // 131 | // 摘要: 132 | // Gets a system-defined color that has an ARGB value of #FFFFA07A. 133 | LightSalmon, 134 | // 135 | // 摘要: 136 | // Gets a system-defined color that has an ARGB value of #FF20B2AA. 137 | LightSeaGreen, 138 | // 139 | // 摘要: 140 | // Gets a system-defined color that has an ARGB value of #FF87CEFA. 141 | LightSkyBlue, 142 | // 143 | // 摘要: 144 | // Gets a system-defined color that has an ARGB value of #FF778899. 145 | LightSlateGray, 146 | // 147 | // 摘要: 148 | // Gets a system-defined color that has an ARGB value of #FFB0C4DE. 149 | LightSteelBlue, 150 | // 151 | // 摘要: 152 | // Gets a system-defined color that has an ARGB value of #FFFFFFE0. 153 | LightYellow, 154 | // 155 | // 摘要: 156 | // Gets a system-defined color that has an ARGB value of #FF00FF00. 157 | Lime, 158 | // 159 | // 摘要: 160 | // Gets a system-defined color that has an ARGB value of #FF808000. 161 | Olive, 162 | // 163 | // 摘要: 164 | // Gets a system-defined color that has an ARGB value of #FF6B8E23. 165 | OliveDrab, 166 | // 167 | // 摘要: 168 | // Gets a system-defined color that has an ARGB value of #FFFFA500. 169 | Orange, 170 | // 171 | // 摘要: 172 | // Gets a system-defined color that has an ARGB value of #FFFF4500. 173 | OrangeRed, 174 | // 175 | // 摘要: 176 | // Gets a system-defined color that has an ARGB value of #FFC0C0C0. 177 | Silver, 178 | // 179 | // 摘要: 180 | // Gets a system-defined color that has an ARGB value of #FF87CEEB. 181 | SkyBlue, 182 | // 183 | // 摘要: 184 | // Gets a system-defined color that has an ARGB value of #FF6A5ACD. 185 | SlateBlue, 186 | // 187 | // 摘要: 188 | // Gets a system-defined color that has an ARGB value of #FF708090. 189 | SlateGray, 190 | // 191 | // 摘要: 192 | // Gets a system-defined color that has an ARGB value of #FFFFFAFA. 193 | Snow, 194 | // 195 | // 摘要: 196 | // Gets a system-defined color that has an ARGB value of #FF00FF7F. 197 | SpringGreen, 198 | // 199 | // 摘要: 200 | // Gets a system-defined color that has an ARGB value of #FF4682B4. 201 | SteelBlue, 202 | // 203 | // 摘要: 204 | // Gets a system-defined color that has an ARGB value of #FFD2B48C. 205 | Tan, 206 | // 207 | // 摘要: 208 | // Gets a system-defined color that has an ARGB value of #FF008080. 209 | Teal, 210 | // 211 | // 摘要: 212 | // Gets a system-defined color that has an ARGB value of #FFD8BFD8. 213 | Thistle, 214 | // 215 | // 摘要: 216 | // Gets a system-defined color that has an ARGB value of #FFFF6347. 217 | Tomato, 218 | // 219 | // 摘要: 220 | // Gets a system-defined color. 221 | Transparent, 222 | // 223 | // 摘要: 224 | // Gets a system-defined color that has an ARGB value of #FF40E0D0. 225 | Turquoise, 226 | // 227 | // 摘要: 228 | // Gets a system-defined color that has an ARGB value of #FFEE82EE. 229 | Violet, 230 | // 231 | // 摘要: 232 | // Gets a system-defined color that has an ARGB value of #FFF5DEB3. 233 | Wheat, 234 | // 235 | // 摘要: 236 | // Gets a system-defined color that has an ARGB value of #FFFFFFFF. 237 | White, 238 | // 239 | // 摘要: 240 | // Gets a system-defined color that has an ARGB value of #FFF5F5F5. 241 | WhiteSmoke, 242 | // 243 | // 摘要: 244 | // Gets a system-defined color that has an ARGB value of #FFA0522D. 245 | Sienna, 246 | // 247 | // 摘要: 248 | // Gets a system-defined color that has an ARGB value of #FFE6E6FA. 249 | Lavender, 250 | // 251 | // 摘要: 252 | // Gets a system-defined color that has an ARGB value of #FFFFF5EE. 253 | SeaShell, 254 | // 255 | // 摘要: 256 | // Gets a system-defined color that has an ARGB value of #FFF4A460. 257 | SandyBrown, 258 | // 259 | // 摘要: 260 | // Gets a system-defined color that has an ARGB value of #FFDA70D6. 261 | Orchid, 262 | // 263 | // 摘要: 264 | // Gets a system-defined color that has an ARGB value of #FFEEE8AA. 265 | PaleGoldenrod, 266 | // 267 | // 摘要: 268 | // Gets a system-defined color that has an ARGB value of #FF98FB98. 269 | PaleGreen, 270 | // 271 | // 摘要: 272 | // Gets a system-defined color that has an ARGB value of #FFAFEEEE. 273 | PaleTurquoise, 274 | // 275 | // 摘要: 276 | // Gets a system-defined color that has an ARGB value of #FFDB7093. 277 | PaleVioletRed, 278 | // 279 | // 摘要: 280 | // Gets a system-defined color that has an ARGB value of #FFFFEFD5. 281 | PapayaWhip, 282 | // 283 | // 摘要: 284 | // Gets a system-defined color that has an ARGB value of #FFFFDAB9. 285 | PeachPuff, 286 | // 287 | // 摘要: 288 | // Gets a system-defined color that has an ARGB value of #FFCD853F. 289 | Peru, 290 | // 291 | // 摘要: 292 | // Gets a system-defined color that has an ARGB value of #FFFFC0CB. 293 | Pink, 294 | // 295 | // 摘要: 296 | // Gets a system-defined color that has an ARGB value of #FFDDA0DD. 297 | Plum, 298 | // 299 | // 摘要: 300 | // Gets a system-defined color that has an ARGB value of #FFB0E0E6. 301 | PowderBlue, 302 | // 303 | // 摘要: 304 | // Gets a system-defined color that has an ARGB value of #FF800080. 305 | Purple, 306 | // 307 | // 摘要: 308 | // Gets a system-defined color that has an ARGB value of #FFFF0000. 309 | Red, 310 | // 311 | // 摘要: 312 | // Gets a system-defined color that has an ARGB value of #FFBC8F8F. 313 | RosyBrown, 314 | // 315 | // 摘要: 316 | // Gets a system-defined color that has an ARGB value of #FF4169E1. 317 | RoyalBlue, 318 | // 319 | // 摘要: 320 | // Gets a system-defined color that has an ARGB value of #FF8B4513. 321 | SaddleBrown, 322 | // 323 | // 摘要: 324 | // Gets a system-defined color that has an ARGB value of #FFFA8072. 325 | Salmon, 326 | // 327 | // 摘要: 328 | // Gets a system-defined color that has an ARGB value of #FF2E8B57. 329 | SeaGreen, 330 | // 331 | // 摘要: 332 | // Gets a system-defined color that has an ARGB value of #FFFFFF00. 333 | Yellow, 334 | // 335 | // 摘要: 336 | // Gets a system-defined color that has an ARGB value of #FFF0E68C. 337 | Khaki, 338 | // 339 | // 摘要: 340 | // Gets a system-defined color that has an ARGB value of #FF00FFFF. 341 | Cyan, 342 | // 343 | // 摘要: 344 | // Gets a system-defined color that has an ARGB value of #FF8B008B. 345 | DarkMagenta, 346 | // 347 | // 摘要: 348 | // Gets a system-defined color that has an ARGB value of #FFBDB76B. 349 | DarkKhaki, 350 | // 351 | // 摘要: 352 | // Gets a system-defined color that has an ARGB value of #FF006400. 353 | DarkGreen, 354 | // 355 | // 摘要: 356 | // Gets a system-defined color that has an ARGB value of #FFA9A9A9. 357 | DarkGray, 358 | // 359 | // 摘要: 360 | // Gets a system-defined color that has an ARGB value of #FFB8860B. 361 | DarkGoldenrod, 362 | // 363 | // 摘要: 364 | // Gets a system-defined color that has an ARGB value of #FF008B8B. 365 | DarkCyan, 366 | // 367 | // 摘要: 368 | // Gets a system-defined color that has an ARGB value of #FF00008B. 369 | DarkBlue, 370 | // 371 | // 摘要: 372 | // Gets a system-defined color that has an ARGB value of #FFFFFFF0. 373 | Ivory, 374 | // 375 | // 摘要: 376 | // Gets a system-defined color that has an ARGB value of #FFDC143C. 377 | Crimson, 378 | // 379 | // 摘要: 380 | // Gets a system-defined color that has an ARGB value of #FFFFF8DC. 381 | Cornsilk, 382 | // 383 | // 摘要: 384 | // Gets a system-defined color that has an ARGB value of #FF6495ED. 385 | CornflowerBlue, 386 | // 387 | // 摘要: 388 | // Gets a system-defined color that has an ARGB value of #FFFF7F50. 389 | Coral, 390 | // 391 | // 摘要: 392 | // Gets a system-defined color that has an ARGB value of #FFD2691E. 393 | Chocolate, 394 | // 395 | // 摘要: 396 | // Gets a system-defined color that has an ARGB value of #FF556B2F. 397 | DarkOliveGreen, 398 | // 399 | // 摘要: 400 | // Gets a system-defined color that has an ARGB value of #FF7FFF00. 401 | Chartreuse, 402 | // 403 | // 摘要: 404 | // Gets a system-defined color that has an ARGB value of #FFDEB887. 405 | BurlyWood, 406 | // 407 | // 摘要: 408 | // Gets a system-defined color that has an ARGB value of #FFA52A2A. 409 | Brown, 410 | // 411 | // 摘要: 412 | // Gets a system-defined color that has an ARGB value of #FF8A2BE2. 413 | BlueViolet, 414 | // 415 | // 摘要: 416 | // Gets a system-defined color that has an ARGB value of #FF0000FF. 417 | Blue, 418 | // 419 | // 摘要: 420 | // Gets a system-defined color that has an ARGB value of #FFFFEBCD. 421 | BlanchedAlmond, 422 | // 423 | // 摘要: 424 | // Gets a system-defined color that has an ARGB value of #FF000000. 425 | Black, 426 | // 427 | // 摘要: 428 | // Gets a system-defined color that has an ARGB value of #FFFFE4C4. 429 | Bisque, 430 | // 431 | // 摘要: 432 | // Gets a system-defined color that has an ARGB value of #FFF5F5DC. 433 | Beige, 434 | // 435 | // 摘要: 436 | // Gets a system-defined color that has an ARGB value of #FFF0FFFF. 437 | Azure, 438 | // 439 | // 摘要: 440 | // Gets a system-defined color that has an ARGB value of #FF7FFFD4. 441 | Aquamarine, 442 | // 443 | // 摘要: 444 | // Gets a system-defined color that has an ARGB value of #FF00FFFF. 445 | Aqua, 446 | // 447 | // 摘要: 448 | // Gets a system-defined color that has an ARGB value of #FFFAEBD7. 449 | AntiqueWhite, 450 | // 451 | // 摘要: 452 | // Gets a system-defined color that has an ARGB value of #FFF0F8FF. 453 | AliceBlue, 454 | // 455 | // 摘要: 456 | // Gets a system-defined color that has an ARGB value of #FF5F9EA0. 457 | CadetBlue, 458 | // 459 | // 摘要: 460 | // Gets a system-defined color that has an ARGB value of #FFFF8C00. 461 | DarkOrange, 462 | // 463 | // 摘要: 464 | // Gets a system-defined color that has an ARGB value of #FF9ACD32. 465 | YellowGreen, 466 | // 467 | // 摘要: 468 | // Gets a system-defined color that has an ARGB value of #FF8B0000. 469 | DarkRed, 470 | // 471 | // 摘要: 472 | // Gets a system-defined color that has an ARGB value of #FF4B0082. 473 | Indigo, 474 | // 475 | // 摘要: 476 | // Gets a system-defined color that has an ARGB value of #FFCD5C5C. 477 | IndianRed, 478 | // 479 | // 摘要: 480 | // Gets a system-defined color that has an ARGB value of #FF9932CC. 481 | DarkOrchid, 482 | // 483 | // 摘要: 484 | // Gets a system-defined color that has an ARGB value of #FFF0FFF0. 485 | Honeydew, 486 | // 487 | // 摘要: 488 | // Gets a system-defined color that has an ARGB value of #FFADFF2F. 489 | GreenYellow, 490 | // 491 | // 摘要: 492 | // Gets a system-defined color that has an ARGB value of #FF008000. 493 | Green, 494 | // 495 | // 摘要: 496 | // Gets a system-defined color that has an ARGB value of #FF808080. 497 | Gray, 498 | // 499 | // 摘要: 500 | // Gets a system-defined color that has an ARGB value of #FFDAA520. 501 | Goldenrod, 502 | // 503 | // 摘要: 504 | // Gets a system-defined color that has an ARGB value of #FFFFD700. 505 | Gold, 506 | // 507 | // 摘要: 508 | // Gets a system-defined color that has an ARGB value of #FFF8F8FF. 509 | GhostWhite, 510 | // 511 | // 摘要: 512 | // Gets a system-defined color that has an ARGB value of #FFDCDCDC. 513 | Gainsboro, 514 | // 515 | // 摘要: 516 | // Gets a system-defined color that has an ARGB value of #FFFF00FF. 517 | Fuchsia, 518 | // 519 | // 摘要: 520 | // Gets a system-defined color that has an ARGB value of #FF228B22. 521 | ForestGreen, 522 | // 523 | // 摘要: 524 | // Gets a system-defined color that has an ARGB value of #FFFF69B4. 525 | HotPink, 526 | // 527 | // 摘要: 528 | // Gets a system-defined color that has an ARGB value of #FFB22222. 529 | Firebrick, 530 | // 531 | // 摘要: 532 | // Gets a system-defined color that has an ARGB value of #FFFFFAF0. 533 | FloralWhite, 534 | // 535 | // 摘要: 536 | // Gets a system-defined color that has an ARGB value of #FF1E90FF. 537 | DodgerBlue, 538 | // 539 | // 摘要: 540 | // Gets a system-defined color that has an ARGB value of #FF696969. 541 | DimGray, 542 | // 543 | // 摘要: 544 | // Gets a system-defined color that has an ARGB value of #FF00BFFF. 545 | DeepSkyBlue, 546 | // 547 | // 摘要: 548 | // Gets a system-defined color that has an ARGB value of #FFFF1493. 549 | DeepPink, 550 | // 551 | // 摘要: 552 | // Gets a system-defined color that has an ARGB value of #FF9400D3. 553 | DarkViolet, 554 | // 555 | // 摘要: 556 | // Gets a system-defined color that has an ARGB value of #FF00CED1. 557 | DarkTurquoise, 558 | // 559 | // 摘要: 560 | // Gets a system-defined color that has an ARGB value of #FF2F4F4F. 561 | DarkSlateGray, 562 | // 563 | // 摘要: 564 | // Gets a system-defined color that has an ARGB value of #FF483D8B. 565 | DarkSlateBlue, 566 | // 567 | // 摘要: 568 | // Gets a system-defined color that has an ARGB value of #FF8FBC8F. 569 | DarkSeaGreen, 570 | // 571 | // 摘要: 572 | // Gets a system-defined color that has an ARGB value of #FFE9967A. 573 | DarkSalmon, 574 | } 575 | } 576 | -------------------------------------------------------------------------------- /ExcelCake/Intrusive/Extension/ExportExtension.cs: -------------------------------------------------------------------------------- 1 | using OfficeOpenXml; 2 | using OfficeOpenXml.Style; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Drawing; 8 | //using System.Drawing; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Reflection; 12 | using System.Web; 13 | 14 | namespace ExcelCake.Intrusive 15 | { 16 | public static class ExportExtension 17 | { 18 | private static readonly string _DateTimeFormatStr = "yyyyMMddHHmmssfff"; 19 | private static readonly string _DefaultExcelName = "ExportFile"; 20 | private static readonly string _ExportExcelNameTemplate = "{0}-{1}.xlsx"; 21 | 22 | /// 23 | /// 导出List为Stream数据 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static MemoryStream ExportToExcelStream(this IEnumerable list, string sheetName = "Sheet1") where T : ExcelBase,new() 29 | { 30 | //MemoryStream stream = new MemoryStream(); 31 | //Type type = typeof(T); 32 | 33 | //var exportSetting = new ExportExcelSetting(type); 34 | 35 | //using (ExcelPackage package = new ExcelPackage()) 36 | //{ 37 | // ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName); 38 | // FillExcelWorksheet(worksheet, list, exportSetting); 39 | // package.SaveAs(stream); 40 | //} 41 | //return stream; 42 | var excelDic = new Dictionary>(); 43 | excelDic.Add(sheetName, list as IEnumerable); 44 | return ExportMultiToStream(excelDic); 45 | } 46 | 47 | /// 48 | /// 导出List为byte[]数据 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | public static byte[] ExportToExcelBytes(this IEnumerable list, string sheetName = "Sheet1") where T : ExcelBase, new() 55 | { 56 | //byte[] excelBuffer = null; 57 | //Type type = typeof(T); 58 | 59 | //var exportSetting = new ExportExcelSetting(type); 60 | 61 | //using (ExcelPackage package = new ExcelPackage()) 62 | //{ 63 | // ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName); 64 | // FillExcelWorksheet(worksheet, list, exportSetting); 65 | // excelBuffer = package.GetAsByteArray(); 66 | //} 67 | //return excelBuffer; 68 | var excelDic = new Dictionary>(); 69 | excelDic.Add(sheetName, list as IEnumerable); 70 | return ExportMultiToBytes(excelDic); 71 | } 72 | 73 | /// 74 | /// 导出List为Excel文件 75 | /// 76 | /// 77 | /// 78 | /// 79 | /// 80 | public static string ExportToExcelFile(this IEnumerable list,string cacheDirectory, string sheetName = "Sheet1", string excelName = "") where T : ExcelBase, new() 81 | { 82 | //var dateTime = DateTime.Now.ToString(_dateTimeFormatStr); 83 | //if (excelName == "") 84 | //{ 85 | // excelName = _defaultExcelName; 86 | //} 87 | //if (excelName.IndexOf(".") > -1) 88 | //{ 89 | // excelName = excelName.Substring(0, excelName.IndexOf(".")); 90 | //} 91 | 92 | //var fileName = string.Format(_exportExcelNameTemplate, excelName, dateTime); 93 | //DirectoryInfo dic = new DirectoryInfo(cacheDirectory); 94 | 95 | //if (!dic.Exists) 96 | //{ 97 | // dic.Create(); 98 | //} 99 | 100 | //string downFilePath = Path.Combine(cacheDirectory, fileName); 101 | 102 | //Type type = typeof(T); 103 | //var exportSetting = new ExportExcelSetting(type); 104 | 105 | //using (ExcelPackage package = new ExcelPackage(new FileInfo(downFilePath))) 106 | //{ 107 | // ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName); 108 | // FillExcelWorksheet(worksheet, list, exportSetting); 109 | // package.Save(); 110 | // return downFilePath; 111 | //} 112 | var excelDic = new Dictionary>(); 113 | excelDic.Add(sheetName, list as IEnumerable); 114 | return ExportMultiToFile(excelDic,cacheDirectory,excelName); 115 | } 116 | 117 | /// 118 | /// 导出List为Stream数据 119 | /// 120 | /// 121 | /// 122 | /// 123 | public static MemoryStream ExportMultiToStream(this IDictionary> dic) 124 | { 125 | MemoryStream stream = new MemoryStream(); 126 | 127 | using (ExcelPackage package = new ExcelPackage()) 128 | { 129 | foreach(var item in dic) 130 | { 131 | var types = item.Value.GetType().GetGenericArguments(); 132 | if (types != null && types.Length > 0) 133 | { 134 | var exportSetting = new ExportExcelSetting(types.First()); 135 | if (exportSetting.ExportColumns.Count > 0) 136 | { 137 | var worksheet = package.Workbook.Worksheets.Add(item.Key); 138 | FillExcelWorksheet(worksheet, item.Value, exportSetting); 139 | } 140 | } 141 | } 142 | 143 | package.SaveAs(stream); 144 | } 145 | return stream; 146 | } 147 | 148 | /// 149 | /// 导出List为byte[]数据 150 | /// 151 | /// 152 | /// 153 | /// 154 | /// 155 | public static byte[] ExportMultiToBytes(this IDictionary> dic) 156 | { 157 | byte[] excelBuffer = null; 158 | 159 | using (ExcelPackage package = new ExcelPackage()) 160 | { 161 | foreach (var item in dic) 162 | { 163 | var types = item.Value.GetType().GetGenericArguments(); 164 | if (types != null && types.Length > 0) 165 | { 166 | var exportSetting = new ExportExcelSetting(types.First()); 167 | if (exportSetting.ExportColumns.Count > 0) 168 | { 169 | var worksheet = package.Workbook.Worksheets.Add(item.Key); 170 | FillExcelWorksheet(worksheet, item.Value, exportSetting); 171 | } 172 | } 173 | } 174 | excelBuffer = package.GetAsByteArray(); 175 | } 176 | return excelBuffer; 177 | } 178 | 179 | /// 180 | /// 导出List为Excel文件 181 | /// 182 | /// 183 | /// 184 | /// 185 | /// 186 | public static string ExportMultiToFile(this IDictionary> dic, string cacheDirectory,string excelName = "") 187 | { 188 | var dateTime = DateTime.Now.ToString(_DateTimeFormatStr); 189 | if (excelName == "") 190 | { 191 | excelName = _DefaultExcelName; 192 | } 193 | if (excelName.IndexOf(".") > -1) 194 | { 195 | excelName = excelName.Substring(0, excelName.IndexOf(".")); 196 | } 197 | 198 | var fileName = string.Format(_ExportExcelNameTemplate, excelName, dateTime); 199 | DirectoryInfo dire = new DirectoryInfo(cacheDirectory); 200 | 201 | if (!dire.Exists) 202 | { 203 | dire.Create(); 204 | } 205 | 206 | string downFilePath = Path.Combine(cacheDirectory, fileName); 207 | 208 | using (ExcelPackage package = new ExcelPackage(new FileInfo(downFilePath))) 209 | { 210 | foreach (var item in dic) 211 | { 212 | var types = item.Value.GetType().GetGenericArguments(); 213 | if (types != null && types.Length > 0) 214 | { 215 | var exportSetting = new ExportExcelSetting(types.First()); 216 | if (exportSetting.ExportColumns.Count > 0) 217 | { 218 | var worksheet = package.Workbook.Worksheets.Add(item.Key); 219 | FillExcelWorksheet(worksheet, item.Value, exportSetting); 220 | } 221 | } 222 | } 223 | package.Save(); 224 | return downFilePath; 225 | } 226 | } 227 | 228 | private static void FillExcelWorksheet(ExcelWorksheet sheet, IEnumerable list, ExportExcelSetting exportSetting) where T : ExcelBase 229 | { 230 | if (sheet == null) 231 | { 232 | return; 233 | } 234 | Type type = null; 235 | var types = list.GetType().GetGenericArguments(); 236 | if (types != null && types.Length > 0) 237 | { 238 | type = types.First(); 239 | } 240 | else 241 | { 242 | type = typeof(T); 243 | } 244 | 245 | Color titleColor = Color.White; 246 | Color headColor = Color.White; 247 | Color contentColor = Color.White; 248 | 249 | int titleRowCount = 1; 250 | int startRow = 1; 251 | int startCol = 1; 252 | int endRow = 1; 253 | int endCol = 1; 254 | 255 | if (exportSetting.ExportStyle != null) 256 | { 257 | var title = exportSetting.ExportStyle.Title; 258 | endCol = (exportSetting.ExportColumns?.Count) ?? 1; 259 | 260 | if (exportSetting.ExportStyle.TitleColor != null) 261 | { 262 | titleColor = exportSetting.ExportStyle.TitleColor; 263 | } 264 | 265 | if (exportSetting.ExportStyle.HeadColor != null) 266 | { 267 | headColor = exportSetting.ExportStyle.HeadColor; 268 | } 269 | 270 | if (exportSetting.ExportStyle.ContentColor != null) 271 | { 272 | contentColor = exportSetting.ExportStyle.ContentColor; 273 | } 274 | 275 | if (!string.IsNullOrEmpty(title) && endCol != 1) 276 | { 277 | int titleEndCol = endCol; 278 | if (exportSetting.ExportStyle.TitleColumnSpan > 0) 279 | { 280 | titleEndCol = exportSetting.ExportStyle.TitleColumnSpan; 281 | } 282 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Merge = true; 283 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Value = title; 284 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 285 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 286 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.Font.Bold = exportSetting.ExportStyle.IsTitleBold; 287 | if (exportSetting.ExportStyle.TitleFontSize > 0) 288 | { 289 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.Font.Size = exportSetting.ExportStyle.TitleFontSize; 290 | } 291 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.Fill.PatternType = ExcelFillStyle.Solid; 292 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.Fill.BackgroundColor.SetColor(titleColor); 293 | sheet.Cells[startRow, startCol, endRow, titleEndCol].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 294 | 295 | } 296 | titleRowCount++; 297 | } 298 | 299 | //写入数据 300 | int mergeRowCount = 0; 301 | if(exportSetting.ExportColumns.GroupBy(o => o.MergeText).Any(o => o.Count() > 1&&o.First().MergeText!=null&&o.First().MergeText!=null)) 302 | { 303 | mergeRowCount = 1; 304 | } 305 | int dataStartRow = titleRowCount+ mergeRowCount; 306 | int dataStartCol = 1; 307 | 308 | for (var i = 0; i < exportSetting.ExportColumns.Count; i++) 309 | { 310 | if (mergeRowCount >= 1 && string.IsNullOrEmpty(exportSetting.ExportColumns[i].MergeText)) 311 | { 312 | sheet.Cells[dataStartRow - 1, i + dataStartCol, dataStartRow, i + dataStartCol].Merge = true; 313 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Value = exportSetting.ExportColumns[i].Text; 314 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 315 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 316 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.Font.Bold = exportSetting.ExportStyle.IsHeadBold; 317 | if (exportSetting.ExportStyle.HeadFontSize > 0) 318 | { 319 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.Font.Size = exportSetting.ExportStyle.HeadFontSize; 320 | } 321 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.Fill.PatternType = ExcelFillStyle.Solid; 322 | sheet.Cells[dataStartRow - 1, i + dataStartCol].Style.Fill.BackgroundColor.SetColor(headColor); 323 | sheet.Cells[dataStartRow - 1, i + dataStartCol, dataStartRow, i + dataStartCol].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 324 | } 325 | else if (mergeRowCount >= 1 && !string.IsNullOrEmpty(exportSetting.ExportColumns[i].MergeText)) 326 | { 327 | var mergeList = exportSetting.MergeList.Where(o => o.Key == exportSetting.ExportColumns[i].MergeText)?.ToList(); 328 | 329 | if (mergeList != null && mergeList.Count > 0) 330 | { 331 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol, dataStartRow - mergeRowCount, i + dataStartCol + mergeList.First().Value - 1].Merge = true; 332 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Value = exportSetting.ExportColumns[i].MergeText; 333 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 334 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 335 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.Font.Bold = exportSetting.ExportStyle.IsHeadBold; 336 | if (exportSetting.ExportStyle.HeadFontSize > 0) 337 | { 338 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.Font.Size = exportSetting.ExportStyle.HeadFontSize; 339 | } 340 | 341 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.Fill.PatternType = ExcelFillStyle.Solid; ; 342 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol].Style.Fill.BackgroundColor.SetColor(headColor); 343 | sheet.Cells[dataStartRow - mergeRowCount, i + dataStartCol, dataStartRow - mergeRowCount, i + dataStartCol + mergeList.First().Value - 1].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 344 | exportSetting.MergeList.Remove(mergeList.First()); 345 | } 346 | 347 | sheet.Cells[dataStartRow, i + dataStartCol].Value = exportSetting.ExportColumns[i].Text; 348 | sheet.Cells[dataStartRow, i + dataStartCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 349 | sheet.Cells[dataStartRow, i + dataStartCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 350 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Font.Bold = exportSetting.ExportStyle.IsHeadBold; 351 | if (exportSetting.ExportStyle.HeadFontSize > 0) 352 | { 353 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Font.Size = exportSetting.ExportStyle.HeadFontSize; 354 | } 355 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Fill.PatternType = ExcelFillStyle.Solid; 356 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Fill.BackgroundColor.SetColor(headColor); 357 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 358 | } 359 | else 360 | { 361 | sheet.Cells[dataStartRow, i + dataStartCol].Value = exportSetting.ExportColumns[i].Text; 362 | sheet.Cells[dataStartRow, i + dataStartCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 363 | sheet.Cells[dataStartRow, i + dataStartCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 364 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Font.Bold = exportSetting.ExportStyle.IsHeadBold; 365 | if (exportSetting.ExportStyle.HeadFontSize > 0) 366 | { 367 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Font.Size = exportSetting.ExportStyle.HeadFontSize; 368 | } 369 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Fill.PatternType = ExcelFillStyle.Solid; 370 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Fill.BackgroundColor.SetColor(headColor); 371 | sheet.Cells[dataStartRow, i + dataStartCol].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 372 | } 373 | 374 | int j = 0; 375 | foreach (var item in list) 376 | { 377 | object value = null; 378 | PropertyInfo propertyInfo = type.GetProperty(exportSetting.ExportColumns[i].Value); 379 | value = propertyInfo.GetValue(item, null); 380 | if(value!=null&&value is string) 381 | { 382 | value = ((string)value).TrimStart(exportSetting.ExportColumns[i].Prefix.ToArray()).TrimEnd(exportSetting.ExportColumns[i].Suffix.ToArray()); 383 | } 384 | //try 385 | //{ 386 | // PropertyInfo propertyInfo = type.GetProperty(exportSetting.ExportColumns[i].Value); 387 | // value = propertyInfo.GetValue(item, null); 388 | //} 389 | //catch (Exception ex) 390 | //{ 391 | // value = ""; 392 | //} 393 | 394 | if (value != null && value.ToString()!="") 395 | { 396 | value = exportSetting.ExportColumns[i].Prefix+value+exportSetting.ExportColumns[i].Suffix; 397 | } 398 | 399 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Value = value??""; 400 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; 401 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.VerticalAlignment = ExcelVerticalAlignment.Center; 402 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.Font.Bold = exportSetting.ExportStyle.IsContentBold; 403 | if (exportSetting.ExportStyle.ContentFontSize > 0) 404 | { 405 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.Font.Size = exportSetting.ExportStyle.ContentFontSize; 406 | } 407 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.Fill.PatternType = ExcelFillStyle.Solid; 408 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.Fill.BackgroundColor.SetColor(contentColor); 409 | sheet.Cells[j + dataStartRow + 1, i + dataStartCol].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black); 410 | j++; 411 | } 412 | sheet.Column(i + 1).AutoFit(); 413 | } 414 | } 415 | } 416 | } --------------------------------------------------------------------------------