Skip to content

Worksheet copy preserves comment object but loses comment text #2524

Description

@Sebazzz

EPPlus usage

Commercial use (I have a commercial license)

Environment

Windows

Epplus version

8.7.0

Spreadsheet application

Excel

Description

When copying a worksheet with EPPlus, cell comments/notes on the copied worksheet retain a comment object but lose their text after saving and reopening the workbook.

This occurs for comments on table data cells and was reproduced with both EPPlus 8.5.4 and EPPlus 8.7.0.

Expected behavior

A copied worksheet should preserve both the comment object and its text.

Actual behavior

After saving and reopening the workbook:

• The source worksheet's cell comment and text are intact.
• The copied worksheet's cell has a non-null  Comment  object.
•  Comment.Text  on the copied cell is  null .
• In Excel, the copied cell displays an empty note.

Repro:

using OfficeOpenXml;

const string outputFileName = "worksheet-comment-copy.xlsx";
string outputPath = Path.Combine(AppContext.BaseDirectory, outputFileName);

ExcelPackage.License.SetNonCommercialPersonal("EPPlus note copy POC");

using (ExcelPackage package = new()) {
    ExcelWorksheet source = package.Workbook.Worksheets.Add("Source");
    source.Cells["A1"].Value = "Question";
    source.Cells["A2"].Value = "A table data cell with a note";
    source.Tables.Add(source.Cells["A1:A2"], "Data0000");
    source.Cells["A2"].AddComment("This note must survive the worksheet copy.", "POC");

    ExcelWorksheet copied = package.Workbook.Worksheets.Copy("Source", "Copy");
    copied.Tables[0].Name = "Data2025";

    package.SaveAs(new FileInfo(outputPath));
}

using ExcelPackage reopenedPackage = new(new FileInfo(outputPath));
ExcelComment? sourceComment = reopenedPackage.Workbook.Worksheets["Source"].Cells["A2"].Comment;
ExcelComment? copiedComment = reopenedPackage.Workbook.Worksheets["Copy"].Cells["A2"].Comment;
const string expectedCommentText = "This note must survive the worksheet copy.";
bool sourceHasExpectedText = String.Equals(sourceComment?.Text, expectedCommentText, StringComparison.Ordinal);
bool copiedHasExpectedText = String.Equals(copiedComment?.Text, expectedCommentText, StringComparison.Ordinal);

Console.WriteLine($"Output: {outputPath}");
Console.WriteLine($"Source A2 comment object after save/reopen: {sourceComment is not null}");
Console.WriteLine($"Source A2 note text after save/reopen:     {Describe(sourceComment?.Text)}");
Console.WriteLine($"Copy A2 comment object after save/reopen:   {copiedComment is not null}");
Console.WriteLine($"Copy A2 note text after save/reopen:         {Describe(copiedComment?.Text)}");

return sourceHasExpectedText && copiedHasExpectedText ? 0 : 1;

static string Describe(string? text) => text switch {
    null => "<null>",
    "" => "<empty>",
    _ => text
};
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <RootNamespace>epplus_note_copy</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="EPPlus" Version="8.7.0" />
  </ItemGroup>

</Project>

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions