【发布时间】:2021-06-16 16:17:55
【问题描述】:
我需要一种稳定的方法将 System.Windows.Forms.DataVisualization.Charting 对象作为图片导出到 Excel。首先我需要说我曾经有一个稳定的解决方案,随着 Win 10 的升级和更新逐步降级。我的场景是我有一个带有多个图表的 WinForms 面板。当用户单击一个按钮时,一个过程开始在此面板中循环图表,将它们作为图片一张一张地复制到剪贴板,然后再一张一张地粘贴到 Excel 工作簿。下面给出的代码非常简化。
在 Win 7 下,以下代码可以作为魅力:
Dim stream As New System.IO.MemoryStream()
chart.SaveImage(stream, Imaging.ImageFormat.Png)
Dim bmp As New Bitmap(stream)
Clipboard.SetDataObject(bmp)
xlWorkSheet.Paste(xlWorkSheet.Range("A" + row.ToString))
但是在安装 Win 10 之后,稳定性降低了,粘贴部分开始失败,出现臭名昭著的异常 0x800A03EC。例如,如果面板中有 50 个图表,则在 80% 的情况下,一两个图表会失败。这就是为什么我修改了我的代码并放置了 Try - Catch 块。事实上 2 个这样的块,因为如果第一次尝试失败再试一次,因为我不喜欢 Excel 导出中缺少图表。这个修改后的解决方案适用于 99.5% 的情况,非常完美:
Dim stream As New System.IO.MemoryStream()
ch.SaveImage(stream, Imaging.ImageFormat.Png)
Dim bmp As New Bitmap(stream)
Clipboard.SetDataObject(bmp)
Try
xlWorkSheet.Paste(xlWorkSheet.Range("A" + row.ToString))
Catch
Try
xlWorkSheet.Paste(xlWorkSheet.Range("A" + row.ToString))
Catch
End Try
End Try
最近可能在 Win 10 更新后复制部分 (Clipboard.SetDataObject) 开始严重失败,出现异常“请求的剪贴板操作未成功”。这就是为什么我用重试时间、超时等扩展了 SetDataObject 参数,但这并没有带来改进。然后我再次实现了 2 个块 Try - Catch,这还不够,所以最后我不得不在 Excel 中的图表位置向用户发送一条消息,提示粘贴失败。请注意,在导出过程中,没有人触摸剪贴板或 Excel,因此不会受到用户方面的干扰。
Dim stream As New System.IO.MemoryStream()
ch.SaveImage(stream, Imaging.ImageFormat.Png)
Dim bmp As New Bitmap(stream)
Try
Clipboard.SetDataObject(bmp, False, 16, 100)
Catch
Try
Clipboard.SetDataObject(bmp, False, 16, 100)
Catch
errorClip = True
End Try
End Try
If errorClip = False Then
Try
xlWorkSheet.Paste(xlWorkSheet.Range("A" + row.ToString))
Catch
Try
xlWorkSheet.Paste(xlWorkSheet.Range("A" + row.ToString))
Catch
End Try
End Try
Else : xlWorkSheet.Range("A" + row.ToString).Value = "Error copying chart. Paste it manually."
End If
【问题讨论】: