使用C#将Excel图表工作表复制到剪贴板

时间:2014-08-04 14:19:10

标签: c# excel charts com

我正在写一个C#应用程序。

其中一项任务是打开Excel电子表格并将图表表格粘贴到C#应用程序中。请注意我指的是一个CHART SHEET ...而不是普通工作表中嵌入的图表对象。

我有理由想在这里做到准确。

我使用普通的COM从C#到Excel进行通信......

using using Microsoft.Office.Interop.Excel;  

在普通工作表中嵌入图表的情况下,API可以正常工作。我从工作簿中检索工作表,从工作表中获取chartObject并在chartObject上发布副本按预期工作,即剪贴板的内容就像从Excel本身启动副本一样。

处理图表时情况有所不同。我从工作簿中获取了Charts,然后获得了我感兴趣的Chart实例。一切都很好。但是,在此处对图表发出Copy()不会导致剪贴板看起来像是从Excel启动操作。 CopyPicture也没有帮助,因为pic真的被炸成了不成比例而剪贴板缺少通常的PNG,GIFF,JPEG格式 - Clipboard.getImage()返回null,而doI看到图像在剪贴板中。 Copy()仅在剪贴板上创建预览,数据对象和OLE私有数据格式而不是更多......

//this does not work - it is for chart sheets
Excel.Charts charts = wb.Charts;
Excel.Chart chart = charts["mychartname"];
chart.Copy(); or chart.CopyPicture();    <-- these do not work as expected...


// this works fine but only covers embedded charts
Excel.ChartObjects charts = ws.ChartObjects;
Excel.ChartObject chart = charts["mychartname"];
chart.Copy();

为什么ChartObject上的Copy与Chart上的Copy不同?复制()是一项微不足道的操作......并且看到它不在Chart上工作是一个巨大的惊喜...

有解决方法吗?无论复制操作是从我的C#app以编程方式启动还是通过Excel本身的用户操作,我基本上都希望剪贴板看起来一样。

如果图表表听起来很陌生......它基本上只是一张只有图表的表格。您可以先创建一个基本的嵌入式图表,然后将其(设计选项卡)移动到专用工作表。

谢谢。

2 个答案:

答案 0 :(得分:0)

经过一些试验和错误后,我找到了一个简单且非常可接受的解决方案。

不是在Chart实例上调用Copy(),而是从Chart获取ChartArea并在其上调用Copy。

Excel.Charts charts = wb.Charts;
Excel.Chart chart = charts["mychartname"];
Excel.ChartArea chartArea = chart.ChartArea;
chartArea.Copy();

记得COM释放所有中间COM对象:)

答案 1 :(得分:0)

在现实生活中,要跟踪所有要发布的中间 COM 对象是非常困难的,甚至是不可能的,如果缺少一个就会给您带来麻烦。

这就是为什么 Microsoft 似乎建议在您确定对任何 COM 对象的所有引用都超出范围后简单地传递垃圾收集器的原因:

// Instead of calling releaseComObject on every single COM object we use, we call the GC when they are all out of scope as suggested in
// https://msdn.microsoft.com/en-us/library/aa679807(v=office.11).aspx#officeinteroperabilitych2_part2_usingrco
GC.Collect();
GC.WaitForPendingFinalizers();
// https://web.archive.org/web/20150907193302/https://code.msdn.microsoft.com/office/VBAutomateExcel-b6ecaff3
// GC needs to be called twice in order to get the Finalizers called the first time in, it simply makes a list of what is to be  
// finalized, the second time in, it actually is finalizing. Only then will the object do its automatic ReleaseComObject. 
GC.Collect();
GC.WaitForPendingFinalizers();

参考文献:

https://msdn.microsoft.com/en-us/library/aa679807(v=office.11).aspx#officeinteroperabilitych2_part2_usingrco

https://web.archive.org/web/20150907193302/https://code.msdn.microsoft.com/office/VBAutomateExcel-b6ecaff3