使用 EPPlus 如何生成电子表格,其中数字是数字而不是文本
Using EPPlus how can I generate a spreadsheet where numbers are numbers not text
我正在使用 LoadFromArrays
从 List<object[]>
创建价差 sheet
数组的第一个条目是标题,其他条目可能是数字、文本或日期(但列表中的每个数组都相同)。
生成的 Excel sheet 有绿色三角形警告,表示数字被格式化为文本。
我遍历所有单元格并将它们的格式设置为数字,就像这样ws.Cells[i, j].Style.Numberformat.Format = "0";
但是问题仍然存在,我仍然看到绿色警告,即使当我查看 Format Cell...
对话框时数字格式设置为数字。
我在这里有哪些选择?我有可能更多地了解每列中的类型,但我该如何设置列标题?
有没有比EPPlus更好的解决方案?或者更多post 传播处理sheet 我可以在下载之前做些什么?
由于您使用的是对象数组,它们可以包含数字和看起来像数字的字符串,因此您必须遍历每个对象并确定其类型:
[TestMethod]
public void Object_Type_Write_Test()
{
//
var existingFile = new FileInfo(@"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
//Some data
var list = new List<Object[]>
{
new object[]
{
"111.11",
111.11,
DateTime.Now
}
};
using (var package = new ExcelPackage(existingFile))
{
var ws = package.Workbook.Worksheets.Add("Sheet1");
ws.Cells[1, 1, 2, 2].Style.Numberformat.Format = "0";
ws.Cells[1, 3, 2, 3].Style.Numberformat.Format = "[$-F400]h:mm:ss\ AM/PM";
//This will cause numbers in string to be stored as string in excel regardless of cell format
ws.Cells["A1"].LoadFromArrays(list);
//Have to go through the objects to deal with numbers as strings
for (var i = 0; i < list.Count; i++)
{
for (var j = 0; j < list[i].Count(); j++)
{
if (list[i][j] is string)
ws.Cells[i + 2, j + 1].Value = Double.Parse((string) list[i][j]);
else if (list[i][j] is double)
ws.Cells[i + 2, j + 1].Value = (double)list[i][j];
else
ws.Cells[i + 2, j + 1].Value = list[i][j];
}
}
package.Save();
}
}
有了上面的内容,您会看到下图作为输出 请注意左上角带有绿色箭头的单元格,因为它是由 LoadFromArray
编写的字符串,看起来像一个数字:
我基于 EPPlus LoadFromArray
创建了一个扩展方法 LoadFormulasFromArray
。该方法假定列表中的所有对象都被视为公式(而不是 LoadFromArray
)。总体情况是 Value
和 Formula
属性都采用 string
而不是特定类型。我认为这是一个错误,因为无法区分字符串是 Text
还是 Formula
。实施 Formula
类型将启用重载和类型检查,从而使始终做正确的事情成为可能。
// usage: ws.Cells[2,2].LoadFormulasFromArrays(MyListOfObjectArrays)
public static class EppPlusExtensions
{
public static ExcelRangeBase LoadFormulasFromArrays(this ExcelRange Cells, IEnumerable<object[]> Data)
{
//thanx to Abdullin for the code contribution
ExcelWorksheet _worksheet = Cells.Worksheet;
int _fromRow = Cells.Start.Row;
int _fromCol = Cells.Start.Column;
if (Data == null) throw new ArgumentNullException("data");
int column = _fromCol, row = _fromRow;
foreach (var rowData in Data)
{
column = _fromCol;
foreach (var cellData in rowData)
{
Cells[row, column].Formula = cellData.ToString();
column += 1;
}
row += 1;
}
return Cells[_fromRow, _fromCol, row - 1, column - 1];
}
}
诀窍是不要将数字作为 "raw objects" 传递给 EPPlus,而是正确地转换它们。
以下是我在使用 EPPlus 制作的 DataTable-to-Excel 导出方法中的做法:
if (dc.DataType == typeof(int)) ws.SetValue(row, col, !r.IsNull(dc) ? (int)r[dc] : (int?)null);
else if (dc.DataType == typeof(decimal)) ws.SetValue(row, col, !r.IsNull(dc) ? (decimal)r[dc] : (decimal?)null);
else if (dc.DataType == typeof(double)) ws.SetValue(row, col, !r.IsNull(dc) ? (double)r[dc] : (double?)null);
else if (dc.DataType == typeof(float)) ws.SetValue(row, col, !r.IsNull(dc) ? (float)r[dc] : (float?)null);
else if (dc.DataType == typeof(string)) ws.SetValue(row, col, !r.IsNull(dc) ? (string)r[dc] : null);
else if (dc.DataType == typeof(DateTime))
{
if (!r.IsNull(dc))
{
ws.SetValue(row, col, (DateTime)r[dc]);
// Change the following line if you need a different DateTime format
var dtFormat = "dd/MM/yyyy";
ws.Cells[row, col].Style.Numberformat.Format = dtFormat;
}
else ws.SetValue(row, col, null);
}
重要:值得注意的是 DateTime
值将需要更多工作才能正确处理,因为我们希望以某种方式对其进行格式化并且,可以说,支持列中的 NULL 值:上述方法满足这两个要求。
中发布了完整的代码示例(DataTable 到 Excel 带有 EPPlus 的文件)
我正在使用 LoadFromArrays
List<object[]>
创建价差 sheet
数组的第一个条目是标题,其他条目可能是数字、文本或日期(但列表中的每个数组都相同)。
生成的 Excel sheet 有绿色三角形警告,表示数字被格式化为文本。
我遍历所有单元格并将它们的格式设置为数字,就像这样ws.Cells[i, j].Style.Numberformat.Format = "0";
但是问题仍然存在,我仍然看到绿色警告,即使当我查看 Format Cell...
对话框时数字格式设置为数字。
我在这里有哪些选择?我有可能更多地了解每列中的类型,但我该如何设置列标题?
有没有比EPPlus更好的解决方案?或者更多post 传播处理sheet 我可以在下载之前做些什么?
由于您使用的是对象数组,它们可以包含数字和看起来像数字的字符串,因此您必须遍历每个对象并确定其类型:
[TestMethod]
public void Object_Type_Write_Test()
{
//
var existingFile = new FileInfo(@"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
//Some data
var list = new List<Object[]>
{
new object[]
{
"111.11",
111.11,
DateTime.Now
}
};
using (var package = new ExcelPackage(existingFile))
{
var ws = package.Workbook.Worksheets.Add("Sheet1");
ws.Cells[1, 1, 2, 2].Style.Numberformat.Format = "0";
ws.Cells[1, 3, 2, 3].Style.Numberformat.Format = "[$-F400]h:mm:ss\ AM/PM";
//This will cause numbers in string to be stored as string in excel regardless of cell format
ws.Cells["A1"].LoadFromArrays(list);
//Have to go through the objects to deal with numbers as strings
for (var i = 0; i < list.Count; i++)
{
for (var j = 0; j < list[i].Count(); j++)
{
if (list[i][j] is string)
ws.Cells[i + 2, j + 1].Value = Double.Parse((string) list[i][j]);
else if (list[i][j] is double)
ws.Cells[i + 2, j + 1].Value = (double)list[i][j];
else
ws.Cells[i + 2, j + 1].Value = list[i][j];
}
}
package.Save();
}
}
有了上面的内容,您会看到下图作为输出 请注意左上角带有绿色箭头的单元格,因为它是由 LoadFromArray
编写的字符串,看起来像一个数字:
我基于 EPPlus LoadFromArray
创建了一个扩展方法 LoadFormulasFromArray
。该方法假定列表中的所有对象都被视为公式(而不是 LoadFromArray
)。总体情况是 Value
和 Formula
属性都采用 string
而不是特定类型。我认为这是一个错误,因为无法区分字符串是 Text
还是 Formula
。实施 Formula
类型将启用重载和类型检查,从而使始终做正确的事情成为可能。
// usage: ws.Cells[2,2].LoadFormulasFromArrays(MyListOfObjectArrays)
public static class EppPlusExtensions
{
public static ExcelRangeBase LoadFormulasFromArrays(this ExcelRange Cells, IEnumerable<object[]> Data)
{
//thanx to Abdullin for the code contribution
ExcelWorksheet _worksheet = Cells.Worksheet;
int _fromRow = Cells.Start.Row;
int _fromCol = Cells.Start.Column;
if (Data == null) throw new ArgumentNullException("data");
int column = _fromCol, row = _fromRow;
foreach (var rowData in Data)
{
column = _fromCol;
foreach (var cellData in rowData)
{
Cells[row, column].Formula = cellData.ToString();
column += 1;
}
row += 1;
}
return Cells[_fromRow, _fromCol, row - 1, column - 1];
}
}
诀窍是不要将数字作为 "raw objects" 传递给 EPPlus,而是正确地转换它们。
以下是我在使用 EPPlus 制作的 DataTable-to-Excel 导出方法中的做法:
if (dc.DataType == typeof(int)) ws.SetValue(row, col, !r.IsNull(dc) ? (int)r[dc] : (int?)null);
else if (dc.DataType == typeof(decimal)) ws.SetValue(row, col, !r.IsNull(dc) ? (decimal)r[dc] : (decimal?)null);
else if (dc.DataType == typeof(double)) ws.SetValue(row, col, !r.IsNull(dc) ? (double)r[dc] : (double?)null);
else if (dc.DataType == typeof(float)) ws.SetValue(row, col, !r.IsNull(dc) ? (float)r[dc] : (float?)null);
else if (dc.DataType == typeof(string)) ws.SetValue(row, col, !r.IsNull(dc) ? (string)r[dc] : null);
else if (dc.DataType == typeof(DateTime))
{
if (!r.IsNull(dc))
{
ws.SetValue(row, col, (DateTime)r[dc]);
// Change the following line if you need a different DateTime format
var dtFormat = "dd/MM/yyyy";
ws.Cells[row, col].Style.Numberformat.Format = dtFormat;
}
else ws.SetValue(row, col, null);
}
重要:值得注意的是 DateTime
值将需要更多工作才能正确处理,因为我们希望以某种方式对其进行格式化并且,可以说,支持列中的 NULL 值:上述方法满足这两个要求。