Teknisk artikel

Trådede kommentarer i Excel-filer med Delphi og HotXLS

Generer en projektmappe fra Delphi, forsyn en celle med en kommentar via den klassiske kommentar-API, og Excel 365 arkiverer din tekst under Noter: En gul boks af den gamle skole uden noget Svar-felt, uden forfatter-avatar, uden løs-knap. HotXLS skriver ægte trådede Excel 365-kommentarer via AddThreadedComment og AddThreadedReply på XLSX-motoren, hvilket udsender den dedikerede del xl/threadedComments/threadedCommentN.xml pr. ark og registrerer hver forfatter i person-delen på projektmappeniveau, så den samtale, din kode skriver, er det samme objekt, som en anmelder svarer på i Excel

Forskellen er vigtig, fordi de to funktioner kun ligner hinanden. En note er et flydende tekstfelt; en trådet kommentar er en samtalepost med stabile identifikatorer, et svar-træ, et forfatterregister og et løst-flag — de ting, som et anmeldelses-workflow faktisk kører på. Denne artikel gennemgår OOXML-strukturen først, for når du først ser de to lagringsmodeller side om side, holder enhver adfærdsforskel i Excel oph med at være mystisk

Hvorfor vises mine kommentarer som noter i Excel 365?

Det korte svar: To generationer af kommentarer deler ét gitter, og they live in helt forskellige dele af pakken. Den ældre model — den, som AddComment er rettet mod — gemmer tekst i xl/comments1.xml (indholdstype application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) og placerer boblen via en ledsagende VML-tegningsdel, xl/drawings/vmlDrawing1.vml. Dette par er ældre end båndet; Excel 365 læser det stadig trofast, men den renderer resultatet som en "note" og tilbyder ingen trådnings-brugerflade på den, fordi der ikke er noget i lageret at tråde. Forfatteren er en visningsstreng, positionen is en VML-form, og det er hele modellen

Trådede kommentarer, der blev introduceret med Excel 365, ignorerer VML-laget fuldstændigt

Hvert ark med en samtale bærer sin egen del xl/threadedComments/threadedCommentN.xml under indholdstypen application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, og projektmappen bærer en enkelt del xl/person/person.xml (indholdstype ...spreadsheetml.people+xml), der viser hver deltager én gang. HotXLS eksponerer begge modeller på det samme regneark: AddComment bliver ved med at skrive det ældre par, AddThreadedComment skriver de nye dele. Hvis dit output vises som noter, kaldte du den første API og ønskede den anden. Den ældre model er stadig det rigtige værktøj til visse opgaver — den tidligere artikel om cellekommentarer og hyperlinks i anmeldelses-workflows dækker den i dybden, inklusive XLS-siden — men intet i den kan opgraderes til en tråd

Hvad HotXLS skriver i pakken

HotXLS modellerer hvert svar som et TXLSXThreadedComment-objekt, der bærer en celleforankring (Ref), en identifikator i GUID-stil (Id), en valgfri ParentId, en AuthorId, der opløses via personlisten, et DisplayName-spejl, tekstkroppen, et Done-flag og en ISO-8601 DateTime. Ved gemning bliver hver post til et <threadedComment>-element, hvis t-attribut indeholder identifikatoren, hvis dT-attribut indeholder tidsstemplet, og hvis parentT-attribut — der kun er til stede på under-svar — navngiver forældre-identifikatoren. Excel genopbygger samtaletræet ved at matche parentT med t; der er ingen indlejring i XML'en, blot en flad liste plus referencer

Person-delen er den del, de fleste hjemmelavede implementeringer glemmer. Hver authorId i en trådet kommentar skal opløses til en <person>-post i xl/person/person.xml, forbundet med projektmappens relationer, med sin egen overstyring af indholdstype — ellers har Excel intet visningsnavn at vise. HotXLS håndterer registreringen automatisk: AddThreadedComment slår forfatteren op på projektmappens Persons-liste efter visningsnavn og opretter en post med en ny GUID, når der ikke findes nogen, så efterfølgende kommentarer fra den samme forfatter deler én identitet. Regnearkets relationer får threadedComments-relationen, projektmappens relationer får person-relationen, og indholdstypernes manifest får begge overstyringer, uden at noget af det optræder i din kode

Opbygning af en svarkæde med AddThreadedComment og AddThreadedReply

AddThreadedComment opretter samtalens rod: Dens ParentId forbliver tom, hvilket er det, der markerer den som toppen af tråden. AddThreadedReply tager en ParentRef-parameter — cellereferencen, hvor roden lever — finder roden ved den forankring og stempler det nye svars ParentId med rodens Id. Begge returnerer den nye TXLSXThreadedComment, så du kan indstille tidsstemplet eller den løste tilstand på det objekt, du lige har oprettet:

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Root: TXLSXThreadedComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('forecast.xlsx');
    Sheet := Book.Sheets[0];

    // Conversation root; ParentId stays empty
    Root := Sheet.AddThreadedComment(8, 3,
      'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
    Root.DateTime := '2026-07-06T09:12:00Z';

    // Replies anchor at the same cell; ParentRef names the root cell
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Pipeline export missed the EMEA renewals, re-running', 'Jan Kowalski');
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Confirmed, refreshed figure lands tomorrow', 'Maria Ortiz');

    Book.SaveAs('forecast-reviewed.xlsx');
  finally
    Book.Free;
  end;
end;

To detaljer i den kode fortjener opmærksomhed. For det første videregives Root.Ref frem for en manuelt opbygget streng: Den reference, biblioteket genererede, er garanteret at matche det, som AddThreadedReply vil slå op, hvilket fjerner en hel klasse af forankringsfejl på grund af off-by-one. For det andet blev begge forfattere videregivet som almindelige visningsnavne — personregistret, GUID-identiteterne og authorId-forbindelserne skete alle bag kulisserne. Åbn den gemte fil i Excel 365, og celleforankringen, svarrækkefølgen og de to forskellige deltagere er alle live: Klik på Svar, og Excel tilføjer til den samme tråd, din kode startede

Læsning af en samtale tilbage: round-trip-adfærd

HotXLS kører trådede kommentarer tur-retur fra version 2.122.0: Genåbning af en gemt pakke genopbygger hvert arks samtaleliste og projektmappens deltagerliste ud fra delene, så identifikatorer, svar-links og visningsnavne overlever en fuld læs→skriv-cyklus. Læseren fortolker person.xml før ethvert arkindhold, hvilket er det, der lader hver authorId opløses til et visningsnavn på indlæsningstidspunktet; fortolkede person-identifikatorer bevares som de er, frem for at blive genereret på ny, så en projektmappe, der pendler mellem din kode og Excel, bevarer stabile forfatteridentiteter på tværs af vilkårligt mange ture frem og tilbage

var
  i: Integer;
  Cmt: TXLSXThreadedComment;
begin
  Book.Open('forecast-reviewed.xlsx');
  Sheet := Book.Sheets[0];
  for i := 0 to Sheet.ThreadedComments.Count - 1 do
  begin
    Cmt := Sheet.ThreadedComments[i];
    if Cmt.ParentId = '' then
      Writeln('Root at ', Cmt.Ref, ' by ', Cmt.DisplayName, ': ', Cmt.Text)
    else
      Writeln('  reply by ', Cmt.DisplayName, ': ', Cmt.Text);
  end;
  Writeln('Participants: ', Book.Persons.Count);
end;

Lagringen som en flad liste plus referencer skinner bevidst igennem her: ThreadedComments oplister svar i rækkefølge efter del, og en tom ParentId identificerer hver rod. Hvis du har brug for træstrukturen — f.eks. for at eksportere en anmeldelseslog — skal du først gruppere efter Ref og derefter kæde ParentId til Id inden for hver celles gruppe. Denne bevar-hvad-du-fortolkede-adfærd er ét eksempel på en bredere politik i biblioteket; artiklen om tabsfri round-tripping af temaer, udvidelseslister og beregningskæden dækker, hvordan det samme princip gælder for resten af pakken

Løst-tilstand, tidsstempler og forfatteridentitet

Tre attributter bærer anmeldelsens semantik, og alle tre er skrivbare på de returnerede objekter. Done kortlægges til done-attributten — Excel viser en løst tråd skjult med et Genåbn-link. DateTime er ISO-8601 UTC-oprettelsesstemplet (dT); HotXLS indsætter en fast pladsholder, når du efterlader den tom, så delen altid validerer, men et rigtigt tidsstempel er det, der gør trådhistorikken læsbar, så indstil det. På identitetssiden eksponerer hver TXLSXPerson en ProviderId — typisk None for lokalt oprettede poster — og et UserId, du kan udfylde med en UPN eller e-mail, når dit program kender det:

var
  Root: TXLSXThreadedComment;
  Person: TXLSXPerson;
begin
  Root := Sheet.ThreadedComments.FindAt('D9');
  if Root <> nil then
    Root.Done := True;   // saved as done="1"; Excel shows the thread resolved

  Person := Book.Persons.FindByDisplayName('Maria Ortiz');
  if Person <> nil then
    Person.UserId := 'maria.ortiz@example.com';
end;

Én grænse skal nævnes tydeligt: HotXLS skriver <mentions>-elementet tomt. @-mention-poster — mekanismen, der lyser en kollegas navn op inde i kommentar-teksten og udløser en meddelelse i Microsoft 365 — er ikke modelleret, så tekst, der indeholder et @-tegn, gemmes som almindelig tekst. For en genereret anmeldelses-projektmappe er det sjældent et tab, men hvis dit workflow afhænger af mention-meddelelser, skal du planlægge, at et menneske tilføjer disse inde i Excel. Forfatteridentitet i person-delen parres naturligt med oprindelsesfelterne på projektmappeniveau, der er dækket i projektmappens metadata og dokumentegenskaber, hvilket er der, resten af en genereret fils revisionsspor lever

Hvad gør ældre Excel-versioner med trådede kommentarer?

Excel 2016 og tidligere er ældre end den trådede model, og de ignorerer simpelthen dele, de ikke forstår. Når Excel 365 selv gemmer en trådet samtale, skriver den også en ældre kommentar-skygge — en pladsholder-note, der lyder "[Trådet kommentar]..." — netop for at ældre versioner viser noget ved den forankrede celle. HotXLS udsender kun de trådede dele, uden nogen ældre skygge, så en fil skrevet af din kode viser slet ingen kommentarindikator, når den åbnes i Excel 2016. Hvis dit publikum omfatter installationer før 365, og annotationen skal være synlig der, det ældre AddComment-API forbliver den kompatible kanal; du skal bare undgå at stable begge modeller på den samme celle uden at teste hver Excel-version, du sender til, for hvordan en læser forsoner en note og en tråd på én celle er læserens beslutning, ikke din

Den anden hårde grænse er selve filformatet. Trådede kommentarer er en OOXML-struktur uden modpart i BIFF8, så .xls-siden af HotXLS har ingen trådet API — en projektmappe, der skal forblive i det ældre binære format, er begrænset til klassiske noter. I praksis er beslutnings-tabellen kort: Hvis du skriver .xlsx til Excel 365 eller web/mobil-Excel-læsere, skal du bruge AddThreadedComment og få rigtige samtaler; hvis du målretter mod Excel 2016 eller .xls, skal du bruge AddComment og acceptere note-modellen; hvis du reviderer en fil, du har modtaget, skal du tjekke både ThreadedComments og Comments, fordi en projektmappe, der har levet i begge verdener, legitimt kan bære begge. Den fulde API-flade for begge generationer er dokumenteret på produktsiden for HotXLS Delphi Excel Component