我正在使用 C# Excel 互操作,我想从一个工作表创建图表的副本,但我想在另一张工作表上创建该副本。我尝试了以下方法:
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);
但是当我尝试这样做时,最后一行抛出错误:
An unhandled exception of type 'System.Exception' occurred in projectname.exe
Additional information: Error reading Excel file C:\ ...the file path...\template.xlsx: Value does not fall within the expected range.
我也试过传递一个工作表而不是一个范围:
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);
我现在能想到的唯一其他解决方案是在 VBA 中执行此操作,然后通过互操作执行宏。但可以肯定的是,只需使用互操作而不使用剪贴板,它就可以以一种干净的方式完成。
最佳答案
您已经有了解决方案,但我不会给您一天的鱼,而是给您一个正确的答案,这将帮助您完成任何 C# Excel 编码任务。
Excel 的 C# Interop 模型与 VBA Excel 模型几乎相同。
这意味着将 VBA 录制的宏转换为 C# 是微不足道的。让我们通过将图表移动到不同的工作表这样的练习来尝试一下。
在 Excel 的“开发人员”选项卡中,单击“录制宏”> 右键单击“图表”> 选择“移动图表”> 选择“对象在:Sheet2”> 单击“确定”> 单击“停止宏录制”。
要查看录制的宏,请按 Alt + F11 调出 VB 编辑器:
请看上面的屏幕截图,VBA 如何向您显示 Location() 的第二个参数是 Name,它实际上是一个字符串参数...
让我们将此 VBA 宏转换为 C#:
@Ama 编辑
下面的建议已经过时了,实际上没有必要担心释放 COM 对象,这是在 RELEASE 模式下自动完成的 (DEBUG mode does not)。参见 Hans Passant's answer to "Clean up Excel Interop Objects with IDisposable" .
这里的诀窍是:永远不要对 com 对象使用 2 个点。
注意我是怎么写的:
var sheetSource = workbookWrapper.ComObject.Sheets["Sheet1"];
但是那有两个点,所以我改为这样写:
var workbookComObject = workbookWrapper.ComObject;
var sheetSource = workbookComObject.Sheets["Sheet1"];
引用:How do I properly clean up Excel interop objects?
您将在上面的 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 并且在分配时不使用两个点似乎超出了顶部但至少当我退出 Excel 实例时进程被释放,我不必以编程方式终止 Excel过程!
引用:Microsoft KB: Office application does not quit after automation from .NET client
关于c# - 复制 Excel 图表并将其移动到另一个工作表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33782622/