Skip to content

Commit 66092f5

Browse files
committed
added RL.FileGenerators.Excel
1 parent 43da592 commit 66092f5

10 files changed

+918
-0
lines changed

ExcelFileGenerator.sln

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26403.7
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BDB86825-709D-463D-9B55-4EF880F76065}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RL.FileGenerators.Excel", "src\RL.FileGenerators.Excel\RL.FileGenerators.Excel.csproj", "{61EE90EA-E716-477F-810B-FA62AB31AED6}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{F8ED83ED-2B94-4588-BDFC-0D074A46F3D0}"
11+
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleDemo", "demo\ConsoleDemo\ConsoleDemo.csproj", "{7BB45ECA-C114-4B05-AB55-35545E617E9F}"
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+
{61EE90EA-E716-477F-810B-FA62AB31AED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{61EE90EA-E716-477F-810B-FA62AB31AED6}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{61EE90EA-E716-477F-810B-FA62AB31AED6}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{61EE90EA-E716-477F-810B-FA62AB31AED6}.Release|Any CPU.Build.0 = Release|Any CPU
24+
{7BB45ECA-C114-4B05-AB55-35545E617E9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25+
{7BB45ECA-C114-4B05-AB55-35545E617E9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
26+
{7BB45ECA-C114-4B05-AB55-35545E617E9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
27+
{7BB45ECA-C114-4B05-AB55-35545E617E9F}.Release|Any CPU.Build.0 = Release|Any CPU
28+
EndGlobalSection
29+
GlobalSection(SolutionProperties) = preSolution
30+
HideSolutionNode = FALSE
31+
EndGlobalSection
32+
GlobalSection(NestedProjects) = preSolution
33+
{61EE90EA-E716-477F-810B-FA62AB31AED6} = {BDB86825-709D-463D-9B55-4EF880F76065}
34+
{7BB45ECA-C114-4B05-AB55-35545E617E9F} = {F8ED83ED-2B94-4588-BDFC-0D074A46F3D0}
35+
EndGlobalSection
36+
EndGlobal

demo/ConsoleDemo/ConsoleDemo.csproj

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp1.1</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<ProjectReference Include="..\..\src\RL.FileGenerators.Excel\RL.FileGenerators.Excel.csproj" />
10+
</ItemGroup>
11+
12+
</Project>

demo/ConsoleDemo/Product.cs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using RL.FileGenerators.Excel;
3+
4+
namespace ConsoleDemo
5+
{
6+
public class Product
7+
{
8+
[ExcelColumn("Product Id", 4)]
9+
public int Id { get; set; }
10+
11+
public string Code { get; set; }
12+
13+
[ExcelColumn("Product Name", 1)]
14+
public string Name { get; set; }
15+
16+
[ExcelColumn("Product Price", 3, NumberingFormatString = "#,##0.00")]
17+
public decimal? Price { get; set; }
18+
19+
[ExcelColumn("Product Discount", 2)]
20+
public float Discount { get; set; }
21+
22+
[ExcelColumn("Available Date", 5, NumberFormatId = 22)]
23+
public DateTime AvailableDate { get; set; }
24+
25+
[ExcelColumn("Is Offline", 6)]
26+
public bool IsOffline { get; set; }
27+
28+
[ExcelColumn("NullableBool", 7)]
29+
public bool? NullableBool { get; set; }
30+
}
31+
}

demo/ConsoleDemo/Program.cs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using RL.FileGenerators.Excel;
5+
6+
namespace ConsoleDemo
7+
{
8+
class Program
9+
{
10+
static void Main(string[] args)
11+
{
12+
CreateExcelFileFromCollection();
13+
}
14+
15+
private static void CreateExcelFileFromCollection()
16+
{
17+
List<Product> products = new List<Product>(3);
18+
products.Add(new Product()
19+
{
20+
Code = "P_A",
21+
Discount = 0.1F,
22+
Id = 1,
23+
Name = "ABC",
24+
Price = 6000.85m,
25+
AvailableDate = DateTime.Now
26+
});
27+
products.Add(new Product()
28+
{
29+
Code = "P_B",
30+
Discount = 0.2F,
31+
Id = 2,
32+
Name = "XYZ",
33+
Price = 5500.50m,
34+
AvailableDate = DateTime.Now.AddDays(-3),
35+
IsOffline = true,
36+
NullableBool = true
37+
});
38+
products.Add(new Product()
39+
{
40+
Code = "P_C",
41+
Discount = 0.22F,
42+
Id = 3,
43+
Name = "123",
44+
Price = null,
45+
AvailableDate = DateTime.Now.AddDays(-3),
46+
IsOffline = true,
47+
NullableBool = true
48+
});
49+
products.Add(new Product()
50+
{
51+
Code = "P_D",
52+
Discount = 0.35F,
53+
Id = 4,
54+
Name = "456",
55+
Price = 5800.0m,
56+
AvailableDate = DateTime.Now.AddDays(-5)
57+
});
58+
59+
string fileName = Path.Combine(Directory.GetCurrentDirectory(), "Test.xlsx");
60+
61+
// create .xlsx file as MemoryStream
62+
using (MemoryStream ms = ExcelFileGenerator.CreateStream(products, "Products"))
63+
{
64+
using (FileStream fs = File.Create(fileName))
65+
{
66+
ms.WriteTo(fs);
67+
}
68+
}
69+
70+
// create .xlsx file
71+
//ExcelGenerator.CreateFile(products, "Products", fileName);
72+
}
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace RL.FileGenerators.Excel
6+
{
7+
/*
8+
* the DateTime type doesn't have "ToOADate" method in .NET Standard 1.3, so I have to copy
9+
* its code from coreclr repository https://github.com/dotnet/coreclr/blob/release/1.0.0/src/mscorlib/src/System/DateTime.cs
10+
* and added this extention method.
11+
*/
12+
public static class DateTimeExtension
13+
{
14+
// Number of 100ns ticks per time unit
15+
private const long TicksPerMillisecond = 10000;
16+
private const long TicksPerSecond = TicksPerMillisecond * 1000;
17+
private const long TicksPerMinute = TicksPerSecond * 60;
18+
private const long TicksPerHour = TicksPerMinute * 60;
19+
private const long TicksPerDay = TicksPerHour * 24;
20+
21+
// Number of milliseconds per time unit
22+
private const int MillisPerSecond = 1000;
23+
private const int MillisPerMinute = MillisPerSecond * 60;
24+
private const int MillisPerHour = MillisPerMinute * 60;
25+
private const int MillisPerDay = MillisPerHour * 24;
26+
27+
// Number of days in a non-leap year
28+
private const int DaysPerYear = 365;
29+
// Number of days in 4 years
30+
private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461
31+
// Number of days in 100 years
32+
private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524
33+
// Number of days in 400 years
34+
private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097
35+
36+
// Number of days from 1/1/0001 to 12/31/1600
37+
private const int DaysTo1601 = DaysPer400Years * 4; // 584388
38+
// Number of days from 1/1/0001 to 12/30/1899
39+
private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
40+
// Number of days from 1/1/0001 to 12/31/1969
41+
internal const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162
42+
// Number of days from 1/1/0001 to 12/31/9999
43+
private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059
44+
45+
internal const long MinTicks = 0;
46+
internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
47+
private const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
48+
49+
private const long FileTimeOffset = DaysTo1601 * TicksPerDay;
50+
private const long DoubleDateOffset = DaysTo1899 * TicksPerDay;
51+
// The minimum OA date is 0100/01/01 (Note it's year 100).
52+
// The maximum OA date is 9999/12/31
53+
private const long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
54+
// All OA dates must be greater than (not >=) OADateMinAsDouble
55+
private const double OADateMinAsDouble = -657435.0;
56+
// All OA dates must be less than (not <=) OADateMaxAsDouble
57+
private const double OADateMaxAsDouble = 2958466.0;
58+
59+
private const int DatePartYear = 0;
60+
private const int DatePartDayOfYear = 1;
61+
private const int DatePartMonth = 2;
62+
private const int DatePartDay = 3;
63+
64+
private static readonly int[] DaysToMonth365 = {
65+
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
66+
private static readonly int[] DaysToMonth366 = {
67+
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
68+
69+
public static readonly DateTime MinValue = new DateTime(MinTicks, DateTimeKind.Unspecified);
70+
public static readonly DateTime MaxValue = new DateTime(MaxTicks, DateTimeKind.Unspecified);
71+
72+
private const UInt64 TicksMask = 0x3FFFFFFFFFFFFFFF;
73+
private const UInt64 FlagsMask = 0xC000000000000000;
74+
private const UInt64 LocalMask = 0x8000000000000000;
75+
private const Int64 TicksCeiling = 0x4000000000000000;
76+
private const UInt64 KindUnspecified = 0x0000000000000000;
77+
private const UInt64 KindUtc = 0x4000000000000000;
78+
private const UInt64 KindLocal = 0x8000000000000000;
79+
private const UInt64 KindLocalAmbiguousDst = 0xC000000000000000;
80+
81+
public static double ToOADate(this DateTime dt)
82+
{
83+
long value = dt.Ticks;
84+
85+
if (value == 0)
86+
return 0.0; // Returns OleAut's zero'ed date value.
87+
88+
if (value < TicksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899.
89+
value += DoubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check.
90+
91+
if (value < OADateMinAsTicks)
92+
throw new OverflowException("Arg_OleAutDateInvalid");
93+
94+
// Currently, our max date == OA's max date (12/31/9999), so we don't
95+
// need an overflow check in that direction.
96+
long millis = (value - DoubleDateOffset) / TicksPerMillisecond;
97+
if (millis < 0)
98+
{
99+
long frac = millis % MillisPerDay;
100+
if (frac != 0) millis -= (MillisPerDay + frac) * 2;
101+
}
102+
103+
return (double)millis / MillisPerDay;
104+
}
105+
}
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace RL.FileGenerators.Excel
2+
{
3+
public class DefinedNameData
4+
{
5+
public string Name { get; set; }
6+
public string SheetName { get; set; }
7+
public string Reference { get; set; }
8+
public string ColumnName { get; set; }
9+
public uint RowIndex { get; set; }
10+
11+
public DefinedNameData() { }
12+
13+
public DefinedNameData(string name, string sheetName, string columnName, uint rowIndex)
14+
{
15+
Name = name;
16+
SheetName = sheetName;
17+
ColumnName = columnName;
18+
RowIndex = rowIndex;
19+
Reference = columnName + rowIndex.ToString();
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
3+
namespace RL.FileGenerators.Excel
4+
{
5+
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
6+
public sealed class ExcelColumnAttribute : Attribute
7+
{
8+
/// <summary>
9+
/// the column title
10+
/// </summary>
11+
public string Title { get; private set; }
12+
13+
/// <summary>
14+
/// the column index in the excel, started from 1
15+
/// </summary>
16+
public int Index { get; private set; }
17+
18+
/// <summary>
19+
/// the Excel embedded number format index used to format the value
20+
/// </summary>
21+
public uint NumberFormatId { get; set; }
22+
23+
/// <summary>
24+
/// customized number format string to format the value
25+
/// </summary>
26+
public string NumberingFormatString { get; set; }
27+
28+
public ExcelColumnAttribute(string title, int index)
29+
{
30+
Title = title;
31+
Index = index;
32+
NumberFormatId = uint.MaxValue;
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Reflection;
2+
3+
namespace RL.FileGenerators.Excel
4+
{
5+
public class ExcelColumnProperty
6+
{
7+
public PropertyInfo PropertyInfo { get; set; }
8+
public ExcelColumnAttribute ExcelColumnAttr { get; set; }
9+
public int CellFormatIndex { get; set; }
10+
11+
public ExcelColumnProperty()
12+
{
13+
CellFormatIndex = -1;
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)