使用 spire.XLS & C#

时间:2021-03-27 17:38:21

标签: c# excel datagridview spire.xls

我正在尝试使用 spire.XLS 将 windows 窗体应用程序上手动选择的 datagridview 行导出到 excel 文件,并在最后一行中添加最后一列的总和。 datagridview 数据如下:

dgv

当我在选择第 1 行和最后一行后运行代码时,excel 应如下所示: 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 中最后一行的第一列。我怎样才能得到想要的结果?

另外,如果我多次运行代码,那么数据不应该覆盖,而只是在最后填充的行之后粘贴数据,最好在中间保留一行空白。

这是 datagridview 的样子: dgv

请帮忙

1 个答案:

答案 0 :(得分:1)

您在这里有多个问题。对于初学者来说,如果你想在同一个工作簿中添加多个选择,那么你需要做一些不同的事情......

  1. 检查文件是否已经存在,如果不存在,则创建一个新文件,如果存在则需要“打开”它。

  2. 如果文件已经存在,那么,打开文件后,需要检查工作表“Exported from gridview”是否存在...如果存在,则需要找到最后使用的行并开始在最后一行之后添加其他行。

  3. 最后保存文件。

目前,代码只是简单地“创建”一个新工作簿,如果现有工作簿已经存在,则代码将覆盖现有工作簿。因此,如果您想向“相同”工作簿“添加”其他选择,则需要添加检查文件是否存在的代码,如果存在,请在工作表上找到下一个可用行以将其他项目添加到如上述前 3 个步骤所述。

下面是一个简单的例子,但它没有经过很好的测试,我相信您可能需要调整代码以满足您的要求。

首先,在 GetDgvToTable 方法中,代码在创建表时似乎抓取了错误的行......

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);
}

接下来,您声明您希望将其他选择添加到同一个工作表中,并且在选择之间有一个空行。这在前面已经讨论过。在下面的代码中,它会检查 Excel 文件是否已经存在,如果存在,则打开该文件。接下来检查工作表是否已经存在。如果它不存在,则创建一个新的。

接下来检查是否有任何“先前”选择已添加到工作表中。我对 Spire 不太熟悉,但是,我注意到如果你调用该方法......

sheet.LastRow…

它将返回下一个可用的行……除非工作表为空。当工作表为空时,这将返回一个类似 65,570 的值。我将把这个留给你,以找出一种更优雅的方法来获得下一个空行。在这种情况下,我只是检查 sheet.LastRow 是否超过 60000。如果值超过 60000,那么我假设工作表是空的,只需将下一个可用行设置为 1。我相信有更好的方法这样做。

考虑到所有这些,通过将附加选择添加到先前选择“下方”的同一个工作表,下面对这两种方法的更改似乎可以如您所愿。

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");
}

我希望这有意义并有所帮助。

相关问题