使用 spire.XLS 和 C# 将所选行从 datagridview 导出到 excel
Export selected rows from datagridview to excel using spire.XLS & C#
我正在尝试使用 spire.XLS 将 windows 表单应用程序中 datagridview 的手动选择行导出到 excel 文件,并将最后一列的总和添加到最后一行。 datagridview 数据如下:
当我 运行 选择第一行和最后一行后的代码时,excel 应该如下所示:
这是我的代码:
void ExportBtnXLSXClick(object sender, EventArgs e)
{
Workbook book = new Workbook();
Worksheet sheet = book.Worksheets[0];
sheet.Name = "Exported from gridview";
//Convert data from datagridview to datatable
DataTable dt=GetDgvToTable(dataGridView1);
//Export datatable to excel
sheet.InsertDataTable(dt, true, 1, 1, -1, -1);
//sheet.InsertDataTable(dt, true, 1, 1, true);
sheet.Range[1,1,sheet.LastRow,sheet.LastColumn].AutoFitColumns();
sheet.AllocatedRange.BorderAround(LineStyleType.Thin, borderColor:ExcelColors.Black);
sheet.AllocatedRange.BorderInside(LineStyleType.Thin, borderColor:ExcelColors.Black);
book.SaveToFile(@"C:\Users\Tamal\Desktop\Spire.XLS C#\Report.xlsx", ExcelVersion.Version2013);
book.Dispose();
MessageBox.Show("Export complete");
}
使用辅助方法
public DataTable GetDgvToTable(DataGridView dgv)
{
DataTable dt = new DataTable();
//Column
for (int count = 0; count < dgv.Columns.Count; count++)
{
DataColumn dc = new DataColumn(dgv.Columns[count].Name.ToString());
dt.Columns.Add(dc);
}
//Row
for (int count = 0; count < dgv.SelectedRows.Count; count++)
{
DataRow dr = dt.NewRow();
for (int countsub = 0; countsub < dgv.Columns.Count; countsub++)
//for (int countsub = 0; countsub < dgv.SelectedRows.Count; countsub++)
{
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
}
dt.Rows.Add(dr);
}
decimal total = dataGridView1.SelectedRows.OfType<DataGridViewRow>()
.Sum(t => Convert.ToDecimal(t.Cells[2].Value));
dt.Rows.Add(total);
return dt;
}
但它没有显示我选择的两行,而且总和显示在 excel 中最后一行的第一列。我怎样才能得到想要的结果?
此外,如果我多次 运行 代码,那么数据不应被覆盖,而只是在最后填充的行之后粘贴数据,最好在中间保留一行空白。
数据网格视图如下所示:
请帮忙
您在这里有多个问题。对于初学者来说,如果您想将多个选择添加到同一个工作簿,那么您需要做一些不同的事情……
检查文件是否已经存在,如果不存在,则创建一个新文件,如果存在,则需要“打开”它。
如果文件已经存在,那么打开文件后,需要检查sheet“Exported from gridview”这个作品是否存在……如果存在,那么,您将需要找到最后使用的行并在最后一行之后开始添加其他行。
最后保存文件。
目前,代码只是简单地“创建”一个新的工作簿,然后代码会覆盖现有的工作簿(如果它已经存在)。因此,如果您想向“相同”工作簿“添加”其他选择,则需要添加检查文件是否存在的代码,如果存在,则在工作sheet 上找到下一个可用行按照上述前 3 个步骤中的说明添加其他项目。
下面是一个简单的示例,但它没有经过很好的测试,我相信您可能需要调整代码以满足您的要求。
首先,在 GetDgvToTable
方法中,代码似乎在创建 table 时抓取了错误的行……
for (int count = 0; count < dgv.SelectedRows.Count; count++)
{
DataRow dr = dt.NewRow();
for (int countsub = 0; countsub < dgv.Columns.Count; countsub++)
//for (int countsub = 0; countsub < dgv.SelectedRows.Count; countsub++)
{
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
}
dt.Rows.Add(dr);
}
上面,代码循环遍历“所选行数”。问题出在线上……
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
具体来说,在……
dgv.Rows[count].
这里的代码忽略了“SELECTED”行。换句话说,如果“选定”行是从“第一”行 (0) 开始的连续“选定”行,那么它将起作用。不幸的是,第一个“选定”行可能不一定是网格中的“第一”行。代码错误地做出了这个假设。
要解决此问题,我建议您使用 foreach
遍历网格 SelectedRows
集合来遍历“选定”行。这将确保代码使用“SELECTED”行。代码更改看起来像……
foreach (DataGridViewRow row in dgv.SelectedRows) {
DataRow dr = dt.NewRow();
for (int i = 0; i < row.Cells.Count; i++) {
dr[i] = row.Cells[i].Value.ToString();
}
dt.Rows.Add(dr);
}
接下来,您声明要将其他选择添加到同一作品中sheet,并且选择之间有一个空行。这在前面已经讨论过。在下面的代码中,它检查 Excel 文件是否已经存在,如果存在,则打开该文件。接下来检查工作sheet 是否已经存在。如果不存在,则创建一个新的。
接下来检查是否有任何“以前”的选择已经添加到作品中sheet。我对 Spire 不是很熟悉,但是,我注意到如果您调用该方法...
sheet.LastRow…
它将 return 下一个可用行...除非作品sheet 为空。当 worksheet 为空时,这将 return 像 65,570 这样的值。我将把这个留给您,让您可能想出一种更优雅的方法来获取下一个空行。在这种情况下,我只是检查 sheet.LastRow
是否超过 60000。如果该值超过 60000,那么我假设 sheet 为空并简单地将下一个可用行设置为 1。我相信有更好的方法。
考虑到所有这些,下面对这两种方法的更改似乎可以按照您的意愿进行,方法是将额外的选择添加到同一作品sheet“低于”之前的选择。
public DataTable GetDgvToTable(DataGridView dgv) {
DataTable dt = new DataTable();
//Column
for (int count = 0; count < dgv.Columns.Count; count++) {
DataColumn dc = new DataColumn(dgv.Columns[count].Name.ToString());
dt.Columns.Add(dc);
}
//Row
foreach (DataGridViewRow row in dgv.SelectedRows) {
DataRow dr = dt.NewRow();
for (int i = 0; i < row.Cells.Count; i++) {
dr[i] = row.Cells[i].Value.ToString();
}
dt.Rows.Add(dr);
}
decimal total = dataGridView1.SelectedRows.OfType<DataGridViewRow>()
.Sum(t => Convert.ToDecimal(t.Cells[2].Value));
dt.Rows.Add("","Total",total);
return dt;
}
然后修改导出方法。
private void btnExportToExcel_Click(object sender, EventArgs e) {
Workbook book = new Workbook();
if (File.Exists(@"pathToFile\Report.xlsx")) {
book.LoadFromFile(@"pathToFile\Report.xlsx");
}
Worksheet sheet = book.Worksheets["Exported from gridview"];
if (sheet == null) {
sheet = book.CreateEmptySheet("Exported from gridview");
}
//Convert data from datagridview to datatable
DataTable dt = GetDgvToTable(dataGridView1);
//Export datatable to excel
int startRow = sheet.LastRow + 2;
if (startRow > 60000) {
startRow = 1;
}
sheet.InsertDataTable(dt, true, startRow, 1, -1, -1);
sheet.Range[1, 1, sheet.LastRow, sheet.LastColumn].AutoFitColumns();
sheet.AllocatedRange.BorderAround(LineStyleType.Thin, borderColor: ExcelColors.Black);
sheet.AllocatedRange.BorderInside(LineStyleType.Thin, borderColor: ExcelColors.Black);
book.SaveToFile(@"pathToFile\Report.xlsx", ExcelVersion.Version2013);
book.Dispose();
MessageBox.Show("Export complete");
}
我希望这是有道理的并且有所帮助。
我正在尝试使用 spire.XLS 将 windows 表单应用程序中 datagridview 的手动选择行导出到 excel 文件,并将最后一列的总和添加到最后一行。 datagridview 数据如下:
当我 运行 选择第一行和最后一行后的代码时,excel 应该如下所示:
这是我的代码:
void ExportBtnXLSXClick(object sender, EventArgs e)
{
Workbook book = new Workbook();
Worksheet sheet = book.Worksheets[0];
sheet.Name = "Exported from gridview";
//Convert data from datagridview to datatable
DataTable dt=GetDgvToTable(dataGridView1);
//Export datatable to excel
sheet.InsertDataTable(dt, true, 1, 1, -1, -1);
//sheet.InsertDataTable(dt, true, 1, 1, true);
sheet.Range[1,1,sheet.LastRow,sheet.LastColumn].AutoFitColumns();
sheet.AllocatedRange.BorderAround(LineStyleType.Thin, borderColor:ExcelColors.Black);
sheet.AllocatedRange.BorderInside(LineStyleType.Thin, borderColor:ExcelColors.Black);
book.SaveToFile(@"C:\Users\Tamal\Desktop\Spire.XLS C#\Report.xlsx", ExcelVersion.Version2013);
book.Dispose();
MessageBox.Show("Export complete");
}
使用辅助方法
public DataTable GetDgvToTable(DataGridView dgv)
{
DataTable dt = new DataTable();
//Column
for (int count = 0; count < dgv.Columns.Count; count++)
{
DataColumn dc = new DataColumn(dgv.Columns[count].Name.ToString());
dt.Columns.Add(dc);
}
//Row
for (int count = 0; count < dgv.SelectedRows.Count; count++)
{
DataRow dr = dt.NewRow();
for (int countsub = 0; countsub < dgv.Columns.Count; countsub++)
//for (int countsub = 0; countsub < dgv.SelectedRows.Count; countsub++)
{
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
}
dt.Rows.Add(dr);
}
decimal total = dataGridView1.SelectedRows.OfType<DataGridViewRow>()
.Sum(t => Convert.ToDecimal(t.Cells[2].Value));
dt.Rows.Add(total);
return dt;
}
但它没有显示我选择的两行,而且总和显示在 excel 中最后一行的第一列。我怎样才能得到想要的结果?
此外,如果我多次 运行 代码,那么数据不应被覆盖,而只是在最后填充的行之后粘贴数据,最好在中间保留一行空白。
数据网格视图如下所示:
请帮忙
您在这里有多个问题。对于初学者来说,如果您想将多个选择添加到同一个工作簿,那么您需要做一些不同的事情……
检查文件是否已经存在,如果不存在,则创建一个新文件,如果存在,则需要“打开”它。
如果文件已经存在,那么打开文件后,需要检查sheet“Exported from gridview”这个作品是否存在……如果存在,那么,您将需要找到最后使用的行并在最后一行之后开始添加其他行。
最后保存文件。
目前,代码只是简单地“创建”一个新的工作簿,然后代码会覆盖现有的工作簿(如果它已经存在)。因此,如果您想向“相同”工作簿“添加”其他选择,则需要添加检查文件是否存在的代码,如果存在,则在工作sheet 上找到下一个可用行按照上述前 3 个步骤中的说明添加其他项目。
下面是一个简单的示例,但它没有经过很好的测试,我相信您可能需要调整代码以满足您的要求。
首先,在 GetDgvToTable
方法中,代码似乎在创建 table 时抓取了错误的行……
for (int count = 0; count < dgv.SelectedRows.Count; count++)
{
DataRow dr = dt.NewRow();
for (int countsub = 0; countsub < dgv.Columns.Count; countsub++)
//for (int countsub = 0; countsub < dgv.SelectedRows.Count; countsub++)
{
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
}
dt.Rows.Add(dr);
}
上面,代码循环遍历“所选行数”。问题出在线上……
dr[countsub] = Convert.ToString(dgv.Rows[count].Cells[countsub].Value);
具体来说,在……
dgv.Rows[count].
这里的代码忽略了“SELECTED”行。换句话说,如果“选定”行是从“第一”行 (0) 开始的连续“选定”行,那么它将起作用。不幸的是,第一个“选定”行可能不一定是网格中的“第一”行。代码错误地做出了这个假设。
要解决此问题,我建议您使用 foreach
遍历网格 SelectedRows
集合来遍历“选定”行。这将确保代码使用“SELECTED”行。代码更改看起来像……
foreach (DataGridViewRow row in dgv.SelectedRows) {
DataRow dr = dt.NewRow();
for (int i = 0; i < row.Cells.Count; i++) {
dr[i] = row.Cells[i].Value.ToString();
}
dt.Rows.Add(dr);
}
接下来,您声明要将其他选择添加到同一作品中sheet,并且选择之间有一个空行。这在前面已经讨论过。在下面的代码中,它检查 Excel 文件是否已经存在,如果存在,则打开该文件。接下来检查工作sheet 是否已经存在。如果不存在,则创建一个新的。
接下来检查是否有任何“以前”的选择已经添加到作品中sheet。我对 Spire 不是很熟悉,但是,我注意到如果您调用该方法...
sheet.LastRow…
它将 return 下一个可用行...除非作品sheet 为空。当 worksheet 为空时,这将 return 像 65,570 这样的值。我将把这个留给您,让您可能想出一种更优雅的方法来获取下一个空行。在这种情况下,我只是检查 sheet.LastRow
是否超过 60000。如果该值超过 60000,那么我假设 sheet 为空并简单地将下一个可用行设置为 1。我相信有更好的方法。
考虑到所有这些,下面对这两种方法的更改似乎可以按照您的意愿进行,方法是将额外的选择添加到同一作品sheet“低于”之前的选择。
public DataTable GetDgvToTable(DataGridView dgv) {
DataTable dt = new DataTable();
//Column
for (int count = 0; count < dgv.Columns.Count; count++) {
DataColumn dc = new DataColumn(dgv.Columns[count].Name.ToString());
dt.Columns.Add(dc);
}
//Row
foreach (DataGridViewRow row in dgv.SelectedRows) {
DataRow dr = dt.NewRow();
for (int i = 0; i < row.Cells.Count; i++) {
dr[i] = row.Cells[i].Value.ToString();
}
dt.Rows.Add(dr);
}
decimal total = dataGridView1.SelectedRows.OfType<DataGridViewRow>()
.Sum(t => Convert.ToDecimal(t.Cells[2].Value));
dt.Rows.Add("","Total",total);
return dt;
}
然后修改导出方法。
private void btnExportToExcel_Click(object sender, EventArgs e) {
Workbook book = new Workbook();
if (File.Exists(@"pathToFile\Report.xlsx")) {
book.LoadFromFile(@"pathToFile\Report.xlsx");
}
Worksheet sheet = book.Worksheets["Exported from gridview"];
if (sheet == null) {
sheet = book.CreateEmptySheet("Exported from gridview");
}
//Convert data from datagridview to datatable
DataTable dt = GetDgvToTable(dataGridView1);
//Export datatable to excel
int startRow = sheet.LastRow + 2;
if (startRow > 60000) {
startRow = 1;
}
sheet.InsertDataTable(dt, true, startRow, 1, -1, -1);
sheet.Range[1, 1, sheet.LastRow, sheet.LastColumn].AutoFitColumns();
sheet.AllocatedRange.BorderAround(LineStyleType.Thin, borderColor: ExcelColors.Black);
sheet.AllocatedRange.BorderInside(LineStyleType.Thin, borderColor: ExcelColors.Black);
book.SaveToFile(@"pathToFile\Report.xlsx", ExcelVersion.Version2013);
book.Dispose();
MessageBox.Show("Export complete");
}
我希望这是有道理的并且有所帮助。