将带有图像列的 datagridview 数据复制到剪贴板
Copy datagridview data with image column to clipboard
是否可以将带有图像列的 datagridview 复制到剪贴板并粘贴到 excel。因为我正在使用复制 datagridview 将其粘贴到 excel 上以供 excel 导出,但未复制图像列。有办法解决这个问题吗?
private void copyAlltoClipboard()
{
//to remove the first blank column from datagridview
dataGridView1.RowHeadersVisible = false;
dataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
dataGridView1.SelectAll();
DataObject dataObj = dataGridView1.GetClipboardContent();
if (dataObj != null)
Clipboard.SetDataObject(dataObj);
}
private void button3_Click_1(object sender, EventArgs e)
{
copyAlltoClipboard();
Microsoft.Office.Interop.Excel.Application xlexcel;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlexcel = new Excel.Application();
xlexcel.Visible = true;
xlWorkBook = xlexcel.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
Excel.Range CR = (Excel.Range)xlWorkSheet.Cells[1, 1];
CR.Select();
xlWorkSheet.PasteSpecial(CR, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true);
}
不知道 DataGridView
是如何填充数据的。在下面的示例中,我使用 DataTable
和 Image
列来填充网格。如果您使用其他类型作为网格的数据源,您可能需要调整代码。如果网格不使用 DataSource
... 那么我强烈建议您使用一个,因为它使事情变得容易得多。
当您将“图像”放入工作表时,您使用 Excel“形状”对象,并且形状对象不一定“位于”工作表中的任何特定单元格内。 “形状图像”被放置在细胞的“顶部”并且可能与许多细胞重叠。放置图像后,您可以在图像中设置一个 属性 以特定单元格或单元格组“移动”。
此外,当在您的应用程序中使用任何“COM”引用时(例如 Excel Interop)……那么您的代码将负责管理您的代码创建的“COM”objects/resources。当前代码没有这样做,很可能会导致资源泄漏。您应该“始终”将处理“COM”对象的代码包装到 try/catch/finally
语句中,以确保在 finally
子句中正确释放“COM”对象。这确保即使代码抛出异常,“COM”对象也能正确释放。请注意。
如前所述,我们知道当剪贴板包含多个不同类型的项目时,图像不会被复制……即文本和图像。然而,应该注意的是,如果将“单个”图像复制到剪贴板,那么,该单个图像 CAN/WILL 将被正确粘贴到工作表中的一个范围内。这是我们“可以”将“现有”图像放入工作表的一种方式。换句话说,在这种情况下,我们可以使用数据 table 中的实际 Image
并将其粘贴到工作表中。这将消除跟踪 image
路径的需要,但是,我们必须一次粘贴每个图像。这是下面使用的方法。
因此我们不妨循环遍历网格或更好的数据源,然后手动将每个数据单元格写入 Excel 文件。我们唯一需要知道的是“哪个”列是 Image
列。我们将不得不通过将图像复制到剪贴板,然后将图像粘贴到工作表中的特定范围来以不同方式处理这些图像单元格。
所以,如果我们可以遍历 DataTable
并将每个单元格写入 excel 文件,我们可能遇到的唯一问题是……我们要“如何”将“图像”添加到 Excel 文件中,我们要将其添加到“哪里”?如前所述,添加图像会将其放置在多个单元格的顶部,具体取决于图像的大小、单元格的大小以及我们将图像放置在工作表中的位置。
例如,由于 DataGridViewImageColumn
有一个 属性 允许您“拉伸”或“缩放”图像以“适合”单元格大小,我们不会真正知道“大小”是多少除非我们检查它,否则实际图像是。如果我们不检查图像大小,那么大图像有可能完全覆盖工作表中的许多行和列,从而覆盖这些单元格中的其他数据。下面的代码试图避免这种情况。
下面的代码做了两件事来帮助避免图像与任何其他单元格重叠……1) 我们将所有图像调整为固定大小。 2) 我们将调整 Excel 文件中将保存图像的列,以确保这些单元格的列宽和行高将大于我们在步骤 1 中设置的图像大小。
下面是一个方法,它采用我们要写入 Excel 文件的 DataTable
dt
,一个 int
imageCol
来标识哪个数据中的列 table 是图像列,string
xlImageCol
是一个字符串,用于标识我们希望图像列在 Excel 文件中的哪一列。在此示例中,这类似于“B”列。最后 string
fileNamePath
作为保存 Excel 文件的完整路径和文件名。
遍历代码……最初创建了所有互操作 COM 变量和一个 Image
变量并将其设置为 null.
这些是我们必须在 Excel 文件具有后释放的对象被创建。在 try
部分,创建了 Excel 应用程序,创建了一个新工作簿并设置了第一个工作表,以便我们可以写入。首先创建几个范围并用于设置列和行的大小,以便每个图像都适合工作表中的单个单元格。
接下来是通过 DataTable
的循环…如果该列不是图像列,则代码只是将文本写入工作表中的正确单元格。如果当前列是图像列,则代码将范围设置为指向单个单元格。然后调整图像大小,然后在Clipboard
中设置一个DataObject
。最后将剪贴板“粘贴”到我们之前定义的单个单元格范围内。
之后,循环遍历数据 table 完成,代码循环遍历工作表中的所有形状并将每个图像的 Placement
属性 设置为 xlMoveAndSize
到如果调整其他单元格的大小或调整图像所在的单元格的大小,请确保图像保留在单个单元格中。请记住,这仅适用于一种方式……当单元格大小变得“小于”图像大小时,图像将调整大小。如果单元格大小“大于”图像大小,则图像将保持其原始大小。
最后在 try/catch/finally
语句的 finally
部分,代码保存并关闭 Excel 文件并释放除 [=13= 之外的所有 COM 对象] 对象。
下面是上述内容的完整示例。在示例中使用了三个不同类型的不同图像,为了方便起见,我将它们张贴在这里。显然,当保存到您的机器时,您可能需要更改图像的文件路径。
下面显示了在代码中创建的表单和 DataGridView
。按下按钮将创建表格下方显示的 Excel 文件。
最后,不知道您是否必须使用 Excel Interop。在许多情况下,您别无选择。但是,如果您确实有选择,我强烈建议您为此使用第三方 Excel 库。我建议你看看 EPPlus。有些是免费的……有些则不是。 Excel Interop 出了名的慢,还有其他问题……只是一个想法。
DataTable GridTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
dataGridView1.DataSource = GridTable;
DataGridViewImageColumn imageColumn = (DataGridViewImageColumn)dataGridView1.Columns[1];
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
imageColumn.ImageLayout = DataGridViewImageCellLayout.Stretch;
}
private void button1_Click(object sender, EventArgs e) {
WriteDT_To_Excel(GridTable, 1, "B", @"D:\Test\Images\_excelWS.xlsx");
}
private void WriteDT_To_Excel(DataTable dt, int imageCol, string xlImageCol, string fileNamePath) {
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
Excel.Worksheet xlWorkSheet = null;
Image image1 = null;
Excel.Range range1 = null;
try {
xlApp = new Excel.Application();
//xlApp.Visible = true;
xlWorkBook = xlApp.Workbooks.Add();
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets[1];
range1 = xlWorkSheet.Range[xlImageCol + 1, xlImageCol + 1];
range1.ColumnWidth = 20;
range1 = xlWorkSheet.Range["A1", "A" + dt.Rows.Count.ToString()];
range1.RowHeight = 80;
int xRow = 1;
int xCol = 1;
foreach (DataRow row in dt.Rows) {
for (int col = 0; col < dt.Columns.Count; col++) {
if (col == imageCol) {
range1 = (Excel.Range)xlWorkSheet.Cells[xRow, xCol++];
if (row[col] != DBNull.Value) {
using (image1 = (Image)row[col]) {
image1 = new Bitmap(image1, new Size(100, 100));
Clipboard.SetDataObject(image1, true);
xlWorkSheet.Paste(range1);
}
}
}
else {
xlWorkSheet.Cells[xRow, xCol++] = row[col];
}
}
xRow++;
xCol = 1;
}
// lock each image onto the cells underneath it - in this case one cell
foreach (Excel.Shape shape in xlWorkSheet.Shapes) {
shape.Placement = Excel.XlPlacement.xlMoveAndSize;
}
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
finally {
if (xlWorkSheet != null) {
Marshal.ReleaseComObject(xlWorkSheet);
}
if (xlWorkBook != null) {
xlWorkBook.SaveAs(fileNamePath);
xlWorkBook.Close();
Marshal.ReleaseComObject(xlWorkBook);
}
if (xlApp != null) {
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
if (image1 != null) {
image1.Dispose();
}
if (range1 != null) {
Marshal.ReleaseComObject(range1);
}
}
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("Col1", typeof(string));
dt.Columns.Add("ImgCol", typeof(Image));
dt.Columns.Add("Col3", typeof(string));
FillTable(dt);
return dt;
}
private void FillTable(DataTable dt) {
Image img1 = Image.FromFile(@"D:\Test\Images\SO_1.bmp");
dt.Rows.Add("1", img1, "Hello");
img1 = Image.FromFile(@"D:\Test\Images\SO_2.jpg");
dt.Rows.Add("2", img1, "Goodbye");
img1 = Image.FromFile(@"D:\Test\Images\SO_3.png");
dt.Rows.Add("3", img1, "");
img1 = Image.FromFile(@"D:\Test\Images\SO_3.png");
dt.Rows.Add("4", img1, "Whatever");
dt.Rows.Add("5");
}
我希望这有道理并有所帮助。
是否可以将带有图像列的 datagridview 复制到剪贴板并粘贴到 excel。因为我正在使用复制 datagridview 将其粘贴到 excel 上以供 excel 导出,但未复制图像列。有办法解决这个问题吗?
private void copyAlltoClipboard()
{
//to remove the first blank column from datagridview
dataGridView1.RowHeadersVisible = false;
dataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
dataGridView1.SelectAll();
DataObject dataObj = dataGridView1.GetClipboardContent();
if (dataObj != null)
Clipboard.SetDataObject(dataObj);
}
private void button3_Click_1(object sender, EventArgs e)
{
copyAlltoClipboard();
Microsoft.Office.Interop.Excel.Application xlexcel;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlexcel = new Excel.Application();
xlexcel.Visible = true;
xlWorkBook = xlexcel.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
Excel.Range CR = (Excel.Range)xlWorkSheet.Cells[1, 1];
CR.Select();
xlWorkSheet.PasteSpecial(CR, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true);
}
不知道 DataGridView
是如何填充数据的。在下面的示例中,我使用 DataTable
和 Image
列来填充网格。如果您使用其他类型作为网格的数据源,您可能需要调整代码。如果网格不使用 DataSource
... 那么我强烈建议您使用一个,因为它使事情变得容易得多。
当您将“图像”放入工作表时,您使用 Excel“形状”对象,并且形状对象不一定“位于”工作表中的任何特定单元格内。 “形状图像”被放置在细胞的“顶部”并且可能与许多细胞重叠。放置图像后,您可以在图像中设置一个 属性 以特定单元格或单元格组“移动”。
此外,当在您的应用程序中使用任何“COM”引用时(例如 Excel Interop)……那么您的代码将负责管理您的代码创建的“COM”objects/resources。当前代码没有这样做,很可能会导致资源泄漏。您应该“始终”将处理“COM”对象的代码包装到 try/catch/finally
语句中,以确保在 finally
子句中正确释放“COM”对象。这确保即使代码抛出异常,“COM”对象也能正确释放。请注意。
如前所述,我们知道当剪贴板包含多个不同类型的项目时,图像不会被复制……即文本和图像。然而,应该注意的是,如果将“单个”图像复制到剪贴板,那么,该单个图像 CAN/WILL 将被正确粘贴到工作表中的一个范围内。这是我们“可以”将“现有”图像放入工作表的一种方式。换句话说,在这种情况下,我们可以使用数据 table 中的实际 Image
并将其粘贴到工作表中。这将消除跟踪 image
路径的需要,但是,我们必须一次粘贴每个图像。这是下面使用的方法。
因此我们不妨循环遍历网格或更好的数据源,然后手动将每个数据单元格写入 Excel 文件。我们唯一需要知道的是“哪个”列是 Image
列。我们将不得不通过将图像复制到剪贴板,然后将图像粘贴到工作表中的特定范围来以不同方式处理这些图像单元格。
所以,如果我们可以遍历 DataTable
并将每个单元格写入 excel 文件,我们可能遇到的唯一问题是……我们要“如何”将“图像”添加到 Excel 文件中,我们要将其添加到“哪里”?如前所述,添加图像会将其放置在多个单元格的顶部,具体取决于图像的大小、单元格的大小以及我们将图像放置在工作表中的位置。
例如,由于 DataGridViewImageColumn
有一个 属性 允许您“拉伸”或“缩放”图像以“适合”单元格大小,我们不会真正知道“大小”是多少除非我们检查它,否则实际图像是。如果我们不检查图像大小,那么大图像有可能完全覆盖工作表中的许多行和列,从而覆盖这些单元格中的其他数据。下面的代码试图避免这种情况。
下面的代码做了两件事来帮助避免图像与任何其他单元格重叠……1) 我们将所有图像调整为固定大小。 2) 我们将调整 Excel 文件中将保存图像的列,以确保这些单元格的列宽和行高将大于我们在步骤 1 中设置的图像大小。
下面是一个方法,它采用我们要写入 Excel 文件的 DataTable
dt
,一个 int
imageCol
来标识哪个数据中的列 table 是图像列,string
xlImageCol
是一个字符串,用于标识我们希望图像列在 Excel 文件中的哪一列。在此示例中,这类似于“B”列。最后 string
fileNamePath
作为保存 Excel 文件的完整路径和文件名。
遍历代码……最初创建了所有互操作 COM 变量和一个 Image
变量并将其设置为 null.
这些是我们必须在 Excel 文件具有后释放的对象被创建。在 try
部分,创建了 Excel 应用程序,创建了一个新工作簿并设置了第一个工作表,以便我们可以写入。首先创建几个范围并用于设置列和行的大小,以便每个图像都适合工作表中的单个单元格。
接下来是通过 DataTable
的循环…如果该列不是图像列,则代码只是将文本写入工作表中的正确单元格。如果当前列是图像列,则代码将范围设置为指向单个单元格。然后调整图像大小,然后在Clipboard
中设置一个DataObject
。最后将剪贴板“粘贴”到我们之前定义的单个单元格范围内。
之后,循环遍历数据 table 完成,代码循环遍历工作表中的所有形状并将每个图像的 Placement
属性 设置为 xlMoveAndSize
到如果调整其他单元格的大小或调整图像所在的单元格的大小,请确保图像保留在单个单元格中。请记住,这仅适用于一种方式……当单元格大小变得“小于”图像大小时,图像将调整大小。如果单元格大小“大于”图像大小,则图像将保持其原始大小。
最后在 try/catch/finally
语句的 finally
部分,代码保存并关闭 Excel 文件并释放除 [=13= 之外的所有 COM 对象] 对象。
下面是上述内容的完整示例。在示例中使用了三个不同类型的不同图像,为了方便起见,我将它们张贴在这里。显然,当保存到您的机器时,您可能需要更改图像的文件路径。
下面显示了在代码中创建的表单和 DataGridView
。按下按钮将创建表格下方显示的 Excel 文件。
最后,不知道您是否必须使用 Excel Interop。在许多情况下,您别无选择。但是,如果您确实有选择,我强烈建议您为此使用第三方 Excel 库。我建议你看看 EPPlus。有些是免费的……有些则不是。 Excel Interop 出了名的慢,还有其他问题……只是一个想法。
DataTable GridTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
dataGridView1.DataSource = GridTable;
DataGridViewImageColumn imageColumn = (DataGridViewImageColumn)dataGridView1.Columns[1];
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
imageColumn.ImageLayout = DataGridViewImageCellLayout.Stretch;
}
private void button1_Click(object sender, EventArgs e) {
WriteDT_To_Excel(GridTable, 1, "B", @"D:\Test\Images\_excelWS.xlsx");
}
private void WriteDT_To_Excel(DataTable dt, int imageCol, string xlImageCol, string fileNamePath) {
Excel.Application xlApp = null;
Excel.Workbook xlWorkBook = null;
Excel.Worksheet xlWorkSheet = null;
Image image1 = null;
Excel.Range range1 = null;
try {
xlApp = new Excel.Application();
//xlApp.Visible = true;
xlWorkBook = xlApp.Workbooks.Add();
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets[1];
range1 = xlWorkSheet.Range[xlImageCol + 1, xlImageCol + 1];
range1.ColumnWidth = 20;
range1 = xlWorkSheet.Range["A1", "A" + dt.Rows.Count.ToString()];
range1.RowHeight = 80;
int xRow = 1;
int xCol = 1;
foreach (DataRow row in dt.Rows) {
for (int col = 0; col < dt.Columns.Count; col++) {
if (col == imageCol) {
range1 = (Excel.Range)xlWorkSheet.Cells[xRow, xCol++];
if (row[col] != DBNull.Value) {
using (image1 = (Image)row[col]) {
image1 = new Bitmap(image1, new Size(100, 100));
Clipboard.SetDataObject(image1, true);
xlWorkSheet.Paste(range1);
}
}
}
else {
xlWorkSheet.Cells[xRow, xCol++] = row[col];
}
}
xRow++;
xCol = 1;
}
// lock each image onto the cells underneath it - in this case one cell
foreach (Excel.Shape shape in xlWorkSheet.Shapes) {
shape.Placement = Excel.XlPlacement.xlMoveAndSize;
}
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
finally {
if (xlWorkSheet != null) {
Marshal.ReleaseComObject(xlWorkSheet);
}
if (xlWorkBook != null) {
xlWorkBook.SaveAs(fileNamePath);
xlWorkBook.Close();
Marshal.ReleaseComObject(xlWorkBook);
}
if (xlApp != null) {
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
if (image1 != null) {
image1.Dispose();
}
if (range1 != null) {
Marshal.ReleaseComObject(range1);
}
}
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("Col1", typeof(string));
dt.Columns.Add("ImgCol", typeof(Image));
dt.Columns.Add("Col3", typeof(string));
FillTable(dt);
return dt;
}
private void FillTable(DataTable dt) {
Image img1 = Image.FromFile(@"D:\Test\Images\SO_1.bmp");
dt.Rows.Add("1", img1, "Hello");
img1 = Image.FromFile(@"D:\Test\Images\SO_2.jpg");
dt.Rows.Add("2", img1, "Goodbye");
img1 = Image.FromFile(@"D:\Test\Images\SO_3.png");
dt.Rows.Add("3", img1, "");
img1 = Image.FromFile(@"D:\Test\Images\SO_3.png");
dt.Rows.Add("4", img1, "Whatever");
dt.Rows.Add("5");
}
我希望这有道理并有所帮助。