Skip to content

Cloning sheet doesn't clone Drawing part #1787

@SzymonSel

Description

@SzymonSel

Describe the bug
I have a template xlsx file, with template sheet, which in turn are cloned and their content is replaced ie. Cell values and images.
After opening the file, the cell values are unique for each cloned Sheet except for the images which are the same, namely the last replaced image.

Screenshots
image

To Reproduce
I have this code which clones a given Sheet:

    public static async void CloneSheet(SpreadsheetDocument spreadSheet, string sheetName, string newSheetName) {
          // Get the source sheet
          var sheets = spreadSheet.WorkbookPart.Workbook.Sheets;
          var sourceSheet = sheets.Elements<Sheet>().FirstOrDefault(s => s.Name == sheetName);
          if (sourceSheet == null) {
              throw new ArgumentException($"Sheet with name {sheetName} does not exist.");
          }

          // Get the source worksheet part
          var sourceSheetPart = (WorksheetPart)spreadSheet.WorkbookPart.GetPartById(sourceSheet.Id);

          // Create a new worksheet part
          var newSheetPart = spreadSheet.WorkbookPart.AddNewPart<WorksheetPart>();
          newSheetPart.Worksheet = (Worksheet)sourceSheetPart.Worksheet.Clone();

          // Clone the relationships
          foreach (var rel in sourceSheetPart.Parts) {
              newSheetPart.AddPart(rel.OpenXmlPart, rel.RelationshipId);
          }

          // Clone DrawingsPart and its related ImageParts
          if (sourceSheetPart.DrawingsPart != null) {
              var sourceDrawingsPart = sourceSheetPart.DrawingsPart;
              DrawingsPart newDrawingsPart;
              
              if (newSheetPart.DrawingsPart == null) {
                  newDrawingsPart = newSheetPart.AddNewPart<DrawingsPart>();
              } else {
                  newDrawingsPart = newSheetPart.DrawingsPart;
              }

              newDrawingsPart.WorksheetDrawing = (WorksheetDrawing)sourceDrawingsPart.WorksheetDrawing.Clone();

              var imagePartsToClone = sourceDrawingsPart.ImageParts.ToList();

              foreach (var imagePart in imagePartsToClone) {
                  var newImagePart = newDrawingsPart.AddImagePart(imagePart.ContentType);


                  using (var stream = imagePart.GetStream()) {
                          newImagePart.FeedData(stream);
                  }

                  // Update the BlipFill.Blip.Embed.Value to reference the new image part
                  foreach (var blip in newDrawingsPart.WorksheetDrawing.Descendants<DocumentFormat.OpenXml.Drawing.Blip>()) {
                      if (blip.Embed.Value == sourceDrawingsPart.GetIdOfPart(imagePart)) {
                          var newId = newDrawingsPart.GetIdOfPart(newImagePart);
                          blip.Embed.Value = newId;
                      }
                  }
              }
          }

          // Create a new sheet and add it to the workbook
          var newSheetId = spreadSheet.WorkbookPart.GetIdOfPart(newSheetPart);
          var newSheet = new Sheet {
              Id = newSheetId,
              SheetId = sheets.Elements<Sheet>().Max(s => s.SheetId.Value) + 1,
              Name = newSheetName // todo: Ensure the new sheet name is unique
          };

          sheets.Append(newSheet);

          // Save the workbook
          spreadSheet.WorkbookPart.Workbook.Save();
      }

Observed behavior
What I discovered is that the Clone() method on the sourceDrawingsPart.WorksheetDrawing doesn't work and in effect, make all the cloned sheets share the DrawingsPart.

Expected behavior
How can achieve DrawingsPart cloning to work?

Desktop (please complete the following information):

  • OS: MacOS, Windows
  • .NET Target: .NET Core, .NET Framework
  • DocumentFormat.OpenXml Version: 3.1.0, 3.0.2

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions