复制Excel图表并将其移动到另一个工作表
我正在使用C#Excel互操作,我想创build一个图表的副本,但我希望在另一个工作表上的副本。 我已经尝试了以下内容:
Excel.ChartObject chartTemplate = (Excel.ChartObject)sheetSource.ChartObjects("chart 1"); object o = chartTemplate.Duplicate(); Excel.ChartObject chart = (Excel.ChartObject)sheetSource.ChartObjects("chart 2"); chart.Name = "Skew" + expiry.ToString("MMMyy"); range = sheetDestination.Range["T" + chartRowCoutner.ToString()]; chart.Chart.Location(Excel.XlChartLocation.xlLocationAsObject, range);
但是当我尝试这个时,最后一行会抛出一个错误:
在projectname.exe中发生未处理的“System.Exception”types的exception
附加信息:读取Excel文件时出错C:\ …文件path… \ template.xlsx:值不在预期范围内。
我也尝试传递一个表单而不是范围:
chart.Chart.Location(Excel.XlChartLocation.xlLocationAsObject, sheetDestination);
但是这给出了同样的错误。 我无法理解错误的原因或如何解决它/绕过它。
我试图避免把剪贴板带入这个问题,但即使我尝试复制和粘贴,我仍然只能将其粘贴为图像,这实际上并不理想:
Excel.ChartArea chartArea = chart.ChartArea; chartArea.Copy(); range = sheetDestination.Range["T" + chartRowCoutner.ToString()]; // Note that chart is not on the sheet sheetDestination range.PasteSpecial(Excel.XlPasteType.xlPasteAll);
我现在唯一能想到的其他解决scheme是在VBA中执行此操作,然后通过interop执行macros。 但是可以肯定的是,只需使用不带剪贴板的互操作即可完成。
您已经有了解决scheme,但是我不会给您一天的时间,我会给您一个适当的答案,这将有助于您完成任何C#Excel编码任务。
Excel的C#Interop模型几乎与VBA Excel模型相同。
这意味着将VBA 录制的macros转换为C#是很简单的。 让我们尝试一下这样的练习,就像将图表移动到不同的工作表一样。
在Excel的“开发人员”选项卡中,单击录制macros>右键单击图表>select移动图表>select对象:Sheet2>单击确定>单击停止macros录制。
要查看录制的macros按Alt + F11调出VB编辑器:
请参阅上面的屏幕截图,VBA如何显示Location()的第二个参数是Name ,实际上是一个string参数 。
让我们把这个VBAmacros转换成C#:
这里的诀窍是:
切勿使用com对象使用2个点。
请注意我可以怎么写:
var sheetSource = workbookWrapper.ComObject.Sheets["Sheet1"];
但有两个点,所以我写这个:
var workbookComObject = workbookWrapper.ComObject; var sheetSource = workbookComObject.Sheets["Sheet1"];
参考: 如何正确清理Excel互操作对象?
你会在上面的QA中看到AutoReleaseComObject
代码,这个代码像VSTOContrib一样使用。
这里是完整的代码:
using Microsoft.Office.Interop.Excel; ... var missing = Type.Missing; using (AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application> excelApplicationWrapper = new AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application>(new Microsoft.Office.Interop.Excel.Application())) { var excelApplicationWrapperComObject = excelApplicationWrapper.ComObject; excelApplicationWrapperComObject.Visible = true; var excelApplicationWrapperComObjectWkBooks = excelApplicationWrapperComObject.Workbooks; try { using (AutoReleaseComObject<Workbook> workbookWrapper = new AutoReleaseComObject<Workbook>(excelApplicationWrapperComObjectWkBooks.Open(@"C:\Temp\ExcelMoveChart.xlsx", false, false, missing, missing, missing, true, missing, missing, true, missing, missing, missing, missing, missing))) { var workbookComObject = workbookWrapper.ComObject; Worksheet sheetSource = workbookComObject.Sheets["Sheet1"]; ChartObject chartObj = (ChartObject)sheetSource.ChartObjects("Chart 3"); Chart chart = chartObj.Chart; chart.Location(XlChartLocation.xlLocationAsObject, "Sheet2"); ReleaseObject(chart); ReleaseObject(chartObj); ReleaseObject(sheetSource); workbookComObject.Close(false); } } finally { excelApplicationWrapperComObjectWkBooks.Close(); ReleaseObject(excelApplicationWrapperComObjectWkBooks); excelApplicationWrapper.ComObject.Application.Quit(); excelApplicationWrapper.ComObject.Quit(); ReleaseObject(excelApplicationWrapper.ComObject.Application); ReleaseObject(excelApplicationWrapper.ComObject); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } } private static void ReleaseObject(object obj) { try { while (System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0); obj = null; } catch (Exception ex) { obj = null; Console.WriteLine("Unable to release the Object " + ex.ToString()); } }
我知道释放所有的对象,使用GC.Collect,而不是使用两个点,当分配似乎在顶部, 但至less当我退出Excel的实例过程被释放,我不必以编程方式杀死Excel进程!
参考: Microsoft KB:Office应用程序不会退出.NET客户端自动化后
从这里的MSDN文档:
https://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.chart.location.aspx
它指出对于types对象的Name参数:
名称types:System.Object如果Where是xlLocationAsObject,或者如果Where是xlLocationAsNewSheet,则为新工作表的名称,其中embedded图表的工作表的名称。
这与相同链接页面底部的示例有些误导。 从给出的例子中可以看出,实际上应该传递一个表名的string。 下面将复制示例中的相关行(该示例用于复制到新工作表):
chart1.Location(Excel.XlChartLocation.xlLocationAsNewSheet, "Sales");
所以,为了转移到现有的工作表,我会这样做:
chart1.Location(Excel.XlChartLocation.xlLocationAsObject, "ExistingSheetName");
不要传递范围,工作簿或工作表对象。 尝试表单名称的string 。
现在,从上面链接的同一个MSDN文档页面中,如果您想要在页面内重新定位图表时,将其移至另一个表格中,还有其他说明,为便于说明,请在此处重复说明:
如果要将图表移动到工作表上的其他位置,请使用ChartArea的P:Microsoft.Office.Interop.Excel.ChartArea.Top属性和P:Microsoft.Office.Interop.Excel.ChartArea.Left属性。 您可以通过使用ChartArea属性来获取图表的ChartArea对象。
如果您要将图表移至现有图纸,请注意不要将图表与现有数据重叠。 如果是这样,你将不得不单独编码。
这不是你问的问题的答案,但可能是有成效的
如果您正在制作一个副本并对其进行编辑,那么这不是一个解决scheme
如果你真的只是复制图表,我build议使用Excel的“相机”function。 它基本上创build了一个窗口到另一个工作表 – 你可以通过编程的方式来做到这一点,它是有据可查的,但是有一点我知道的特点,我认为如果我没有指出,我会失去工作。
-E
如果您正在进行编辑并且问题仍然存在,请让我知道,在评论中 – 我已经完成了这一步,然后我只需要回顾一下工作簿,看看我是如何做到的。
“相机选项很好,因为它不会”重新计算“数据 – 所以我想它的运行速度更快; 在大型工作簿的关注。