使用 Open XML 插入列后更新形状和图表位置

问题描述 投票:0回答:1

在 Excel 中,当您选择一列,人民币并选择“插入”时,将插入一个新列,如果受影响的区域中有任何形状或图表,它们会相应地扩展。我正在尝试使用开放 XML SDK 来实现这一点。

如上面的 GIF 所示,我的目标是实现以下目标:

  • 在工作表中插入新列。
  • 更新受影响范围内的形状/图表的位置,以便它们与新列正确对齐(形状和图表的扩展)。

我尝试使用 TwoCellAnchor 方法(如各种资源中所推荐的那样),但我无法理解更新形状/图表位置所涉及的 XML 元素和属性的确切结构。

我注意到在之前的讨论中已经建议了像 Xdr.Marker、A.ColumnId 和 A.ColOffset 这样的类,但这些类似乎并没有直接解决问题。我正在努力确定要操作的正确类和属性,以实现所需的结果。

具有使用 Open XML 和操作形状位置经验的人可以帮助阐明这一点吗?我是否应该使用任何特定的类或方法,或者这是 Open XML SDK 中的限制?任何指导、代码片段或示例将不胜感激。

预先感谢您的协助。

下面是我当前的代码,它在列索引 1 之后插入 3 个新列。

using System;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using A = DocumentFormat.OpenXml.Drawing;
using Xdr = DocumentFormat.OpenXml.Drawing.Spreadsheet;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace insetNewColumnChart
{
    internal class numberOfColumns
    {
        static void Main(string[] args)
        {
            using (SpreadsheetDocument document = SpreadsheetDocument.Open(@"C:\Temp\Chart.xlsx", true))
            {
                string sheetName = "Sheet1"; // Replace with your sheet name
                int columnIndexToInsertAfter = 1;   // Column index to insert after (e.g., 2 for column B)

                InsertColumnsAfterIndex(document, sheetName, columnIndexToInsertAfter);
            }

        }
        static void InsertColumnsAfterIndex(SpreadsheetDocument document, string sheetName, int columnIndex)
        {
            Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == sheetName);

            if (sheet != null)
            {
                WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
                Worksheet worksheet = worksheetPart.Worksheet;

                // Check if the column collection exists
                Columns cs = worksheet.Elements<Columns>().FirstOrDefault();

                if (cs == null)
                {
                    SheetData sd = worksheet.Elements<SheetData>().FirstOrDefault();

                    if (sd != null)
                    {
                        cs = worksheet.InsertBefore(new Columns(), sd);
                    }
                    else
                    {
                        cs = new Columns();
                        worksheet.Append(cs);
                    }
                }

                // Define the width and index range for the new columns
                Column newColumn = new Column
                {
                    Min = (UInt32Value)(columnIndex + 1U),  // Columns are 1-indexed
                    Max = (UInt32Value)(columnIndex + 3U),
                    Width = 20,
                    CustomWidth = true
                };

                cs.Append(newColumn);

                // Update cell references in formulas
                foreach (Cell cell in worksheet.Descendants<Cell>())
                {
                    if (cell.CellFormula != null)
                    {
                        string formula = cell.CellFormula.Text;
                        cell.CellFormula.Text = UpdateFormulaReferences(formula, columnIndex, 3);
                    }
                }

                worksheetPart.Worksheet.Save();
            }
            else
            {
                Console.WriteLine("Sheet not found.");
            }
        }

        static string UpdateFormulaReferences(string formula, int columnIndex, int numberOfColumns)
        {
            for (int i = 0; i < numberOfColumns; i++)
            {
                string oldColumnReference = GetCellReference(columnIndex + i, 1);
                string newColumnReference = GetCellReference(columnIndex + i + numberOfColumns, 1);
                formula = formula.Replace(oldColumnReference, newColumnReference);
            }
            return formula;
        }

        static string GetCellReference(int columnIndex, int rowIndex)
        {
            // Convert column index to column name (e.g., 1 -> A, 2 -> B, ...)
            int dividend = columnIndex;
            string columnName = String.Empty;
            int modulo;

            while (dividend > 0)
            {
                modulo = (dividend - 1) % 26;
                columnName = Convert.ToChar(65 + modulo) + columnName;
                dividend = (dividend - modulo) / 26;
            }

            return columnName + rowIndex;
        }
    }
}
c# openxml openxml-sdk .net-4.8
1个回答
0
投票

要使用 DocumentFormat.OpenXml 库更改电子表格中绘图元素的结束锚点,您可以使用 MarkerType 类的 ToMarker 属性。

ToMarker 属性指定绘图元素的第二个锚点,用于锚定电子表格中形状的底部和右侧。当调整 To 元素中指定的单元格时,形状也会调整。

有关DocumentFormat.OpenXml库中ToMarker类的更多详细信息,您可以参考微软官方文档

© www.soinside.com 2019 - 2024. All rights reserved.