Datagridview-将选定的单元格复制到新的DataTable

时间:2019-04-25 08:04:45

标签: c# datagridview

我需要将数据从DataGridView导出到Excel,但仅导出选定的单元格。 DataGridView绑定到DataTable。我已经看到了很多有关如何复制所选行的示例,但是找不到如何仅将所选单元格复制到新的DataTable中的示例。到目前为止,这是我尝试过的:

  //First, copy structure of DataTable into new one
  DataTable dt = ((DataTable)dgv.DataSource).Clone();

  //Then insert data into new datatable
  foreach (DataGridViewCell cell in dgv.SelectedCells)
  {
    //We get Index of column and row from bounded DataTable 
     int col_indx = ((DataTable)dgv.DataSource).Columns.IndexOf(dgv.Columns[cell.ColumnIndex].Name);
     int row_indx = ((DataTable)dgv.DataSource).Rows.IndexOf(((DataRowView)dgv.Rows[cell.RowIndex].DataBoundItem).Row);

  //First check if row already exists
  if (dt.Columns.Contains(dgv.Columns[cell.ColumnIndex].Name))
            {
                DataRow newrow = dt.NewRow();
                newrow[col_indx] = cell.Value;
                dt.Rows.InsertAt(newrow, row_indx);
            }
            else
            {
               dt.Rows[row_indx][cell_indx] = cell.Value;
            }    

  }
   dt.AcceptChanges();

这部分将数据插入到新的DataTable中,但在单独的行中如果我从同一行中选择了一些单元格。我该如何解决?

编辑:

 for (int i = 0; i < dgv.Rows.Count; i++)
 {
     dt.Rows.Add();
     for (int j = 0; j < dgv.ColumnCount; j++)
     {
        if (dgv.Rows[i].Cells[j].Selected == true)
        {
           dt.Rows[i][j] = dgv.Rows[i].Cells[j].Value;
        }
     }
  }
   dt.AcceptChanges();

这是我能实现的最接近的目标。它将选定的数据复制到新的DataTable中,但不幸的是,它也保留了空行。所以当我从例如选择Datagridview中的单元格时第3行,Excel中的输出将前2行为空。我想避免这种情况,但是如何避免呢?换句话说,我在Datagridview中选择的内容必须从第1行的新Datatable开始,依此类推...

3 个答案:

答案 0 :(得分:1)

您为每一行添加一行。您必须为每个选定的行添加一行。试试这个

 int k=0;
 bool addRow;
 for (int i = 0; i < dgv.Rows.Count; i++)
 {
     addRow=true;
     for (int j = 0; j < dgv.ColumnCount; j++)
     {
        if (dgv.Rows[i].Cells[j].Selected == true)
        {
            if(addRow){
                dt.Rows.Add();
                addRow=false;
                k++;
            }
            dt.Rows[k-1][j] = dgv.Rows[i].Cells[j].Value;
        }
     }
  }
   dt.AcceptChanges();

答案 1 :(得分:0)

您正在遍历每个选定的单元格,并在指定的 row_indx 中创建/插入新行,而无需检查单元格是否属于同一行,以及 dt 是否已在 row_indx 处插入一行。

我建议检查您是否已经在 row_indx 处插入了一行,然后抓取该行并添加到该行(如果没有)没有该行,然后创建新行并添加所选单元格。

答案 2 :(得分:0)

问题解决了。不过,这并不容易。首先,我必须创建一个与绑定DataTable具有相同结构的新DataTable。然后将所有选定的单元格复制到该DataTable中。最后,我使用this answer of Levitikon中的CopyToDataTable方法创建了一个仅包含非空行的新DataTable。这是完整的代码:

//First, copy structure of DataTable into new one
DataTable dt = ((DataTable)dgv.DataSource).Clone();

//Add all selected cells into this DataTable
for (int i = 0; i < dgv.Rows.Count; i++)
 {
     dt.Rows.Add();
     for (int j = 0; j < dgv.ColumnCount; j++)
     {
        if (dgv.Rows[i].Cells[j].Selected == true)
        {
           dt.Rows[i][j] = dgv.Rows[i].Cells[j].Value;
        }
     }
  }
   dt.AcceptChanges();

 // Then create a new DataTable without blank rows
 DataTable final_dt = dt.Rows.Cast<DataRow>()
 .Where(row => !row.ItemArray.All(field => field is DBNull ||
 string.IsNullOrWhiteSpace(field.ToString()))).CopyToDataTable();

现在,我在DataGridView中选择的所有内容都会添加到新的DataTable中,并且一旦我在Excel中导出此DataTable,所有数据就会根据需要从第0行开始。如果有人知道更好/更短的解决方案,请告诉我。