Genereer een werkboek vanuit Delphi, voorzie een cel van annotaties met de klassieke commentaar-API, en Excel 365 archiveert uw tekst onder Notities (Notes): een geel vak in de oude stijl zonder antwoordveld, zonder auteur-avatar en zonder knop om de discussie op te lossen. HotXLS schrijft echte Excel 365 threaded comments via AddThreadedComment en AddThreadedReply in de XLSX-engine. Dit genereert het speciale onderdeel xl/threadedComments/threadedCommentN.xml per werkblad en registreert elke auteur in het person-onderdeel op werkboekniveau, zodat de conversatie die uw code schrijft hetzelfde object is waar een revisor in Excel op antwoordt
Het onderscheid is belangrijk omdat de twee functies er alleen maar hetzelfde uitzien. Een notitie is een zwevend tekstvak; een threaded comment is een conversatierecord met stabiele ID's, een antwoordstructuur, een auteursregister en een vlag 'opgelost' — de zaken waar een revisieworkflow daadwerkelijk op draait. Dit artikel bespreekt eerst de OOXML-structuur, want zodra u de twee opslagmodellen naast elkaar ziet, is geen enkel verschil in gedrag in Excel meer mysterieus
Waarom worden mijn opmerkingen als notities weergegeven in Excel 365?
Het korte antwoord: twee generaties opmerkingen delen hetzelfde raster en ze bevinden zich in totaal verschillende delen van het pakket. Het verouderde model — waar AddComment zich op richt — slaat tekst op in xl/comments1.xml (inhoudstype application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) en positioneert de tekstballon via een bijbehorend VML-tekenonderdeel, xl/drawings/vmlDrawing1.vml. Dat paar dateert van vóór het lint; Excel 365 leest het nog steeds getrouw, maar rendert het resultaat als een "notitie" en biedt er geen threading-UI op aan, omdat er in de opslag niets is om te threaden. De auteur is een weergavestring, de positie is een VML-vorm, en dat is het hele model
Threaded comments, geïntroduceerd in Excel 365, negeren de VML-laag volledig. Elk blad met een conversatie draagt haar eigen xl/threadedComments/threadedCommentN.xml-onderdeel onder het inhoudstype application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, en het werkboek bevat één xl/person/person.xml-onderdeel (inhoudstype ...spreadsheetml.people+xml) dat elke deelnemer eenmalig vermeldt. HotXLS stelt beide modellen beschikbaar op hetzelfde werkblad: AddComment blijft het verouderde paar schrijven, AddThreadedComment schrijft de nieuwe onderdelen. Als uw uitvoer als notities verschijnt, hebt u de eerste API aangeroepen terwijl u de tweede wilde. Het verouderde model is voor sommige taken nog steeds het juiste gereedschap — het eerdere artikel over celopmerkingen en hyperlinks in revisieworkflows behandelt dit in detail, inclusief de XLS-kant — maar er kan niets in worden opgewaardeerd naar een thread
Wat HotXLS in het pakket schrijft
HotXLS modelleert elk antwoord als een TXLSXThreadedComment-object met een celanker (Ref), een ID in GUID-stijl (Id), een optionele ParentId, een AuthorId die via de personenlijst wordt opgelost, een DisplayName-kopie, de tekstinhoud, een Done-vlag en een ISO-8601 DateTime. Bij het opslaan wordt elke invoer een <threadedComment>-element waarvan het attribuut t de identificator bevat, het attribuut dT de tijdstempel en het attribuut parentT — dat alleen aanwezig is op onderliggende antwoorden — de ouder-identificator noemt. Excel reconstrueert de conversatiestructuur door parentT aan t te koppelen; er is geen nesten in de XML, alleen een platte lijst plus verwijzingen
Het person-onderdeel is het stuk dat de meeste handgeschreven implementaties vergeten. Elke authorId in een threaded comment moet verwijzen naar een <person>-invoer in xl/person/person.xml, gekoppeld aan de werkboekrelaties en voorzien van een eigen override voor het inhoudstype — anders heeft Excel geen weergavenaam om te tonen. HotXLS handelt de registratie automatisch af: AddThreadedComment zoekt de auteur op in de lijst Persons van het werkboek op weergavenaam en maakt een vermelding met een nieuwe GUID aan als er nog geen bestaat, zodat opeenvolgende opmerkingen van dezelfde auteur één identiteit delen. De werkbladrelaties krijgen de relatie threadedComments, de werkboekrelaties krijgen de person-relatie en het manifest voor inhoudstypes krijgt beide overrides, zonder dat er iets van in uw code verschijnt
Een antwoordketen bouwen met AddThreadedComment en AddThreadedReply
AddThreadedComment maakt de root van de conversatie aan: de ParentId blijft leeg, wat deze markeert als het begin van de thread. AddThreadedReply neemt een parameter ParentRef aan — de celverwijzing waar de root zich bevindt — vindt de root op dat anker en stempelt de ParentId van het nieuwe antwoord met de Id van de root. Beide retourneren de nieuwe TXLSXThreadedComment, zodat u de tijdstempel of de opgeloste status kunt instellen op het object dat u zojuist hebt gemaakt:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Root: TXLSXThreadedComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('forecast.xlsx');
Sheet := Book.Sheets[0];
// Root van de conversatie; ParentId blijft leeg
Root := Sheet.AddThreadedComment(8, 3,
'Q3-cijfer ziet er laag uit in vergelijking met de pipeline-export', 'Maria Ortiz');
Root.DateTime := '2026-07-06T09:12:00Z';
// Antwoorden zijn verankerd aan dezelfde cel; ParentRef noemt de root-cel
Sheet.AddThreadedReply(8, 3, Root.Ref,
'Pipeline-export miste de EMEA-verlengingen, opnieuw uitvoeren', 'Jan Kowalski');
Sheet.AddThreadedReply(8, 3, Root.Ref,
'Bevestigd, vernieuwd cijfer volgt morgen', 'Maria Ortiz');
Book.SaveAs('forecast-reviewed.xlsx');
finally
Book.Free;
end;
end;
Twee details in die code zijn de moeite waard om op te letten. Ten eerste wordt Root.Ref doorgegeven in plaats van een handmatig opgebouwde string: de referentie die de bibliotheek heeft gegenereerd, komt gegarandeerd overeen met wat AddThreadedReply zal opzoeken, wat een hele klasse van off-by-one ankerbugs elimineert. Ten tweede werden beide auteurs doorgegeven als gewone weergavenamen — het personenregister, de GUID-identiteiten en de bedrading van de authorId vonden allemaal achter de schermen plaats. Open het opgeslagen bestand in Excel 365 en de celverankering, de antwoordvolgorde en de twee verschillende deelnemers zijn allemaal live: klik op Beantwoorden en Excel voegt antwoorden toe aan dezelfde thread die uw code is gestart
Een conversatie teruglezen: gedrag bij heen-en-weerrondes
HotXLS ondersteunt heen-en-weerrondes van threaded comments vanaf versie 2.122.0: het opnieuw openen van een opgeslagen pakket bouwt de conversatielijst van elk werkblad en de deelnemerslijst van het werkboek opnieuw op uit de onderdelen, zodat identificatoren, antwoordlinks en weergavenamen een volledige lees-schrijfcyclus overleven. De lezer ontleedt person.xml vóór de inhoud van de werkbladen, waardoor elke authorId bij het laden kan worden opgelost naar een weergavenaam; ontlede personen-identificatoren blijven behouden zoals ze zijn in plaats van opnieuw te worden gegenereerd, zodat een werkboek dat pendelt tussen uw code en Excel stabiele auteursidentiteiten behoudt over willekeurig veel heen-en-weerrondes
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 op ', Cmt.Ref, ' door ', Cmt.DisplayName, ': ', Cmt.Text)
else
Writeln(' antwoord door ', Cmt.DisplayName, ': ', Cmt.Text);
end;
Writeln('Deelnemers: ', Book.Persons.Count);
end;
De platte lijst-plus-verwijzingen opslag is hier bewust zichtbaar: ThreadedComments somt antwoorden op in de volgorde van de XML-onderdelen, en een lege ParentId identificeert elke root. Als u de boomstructuur nodig hebt — bijvoorbeeld om een revisielogboek te exporteren — gropeer dan eerst op Ref en koppel vervolgens ParentId aan Id binnen de groep van elke cel. Dit gedrag van behouden-wat-is-ontleed is een voorbeeld van een breder beleid in de bibliotheek; het artikel over verliesvrije heen-en-weerrondes van thema's, extensielijsten en de herberekeningsketen (calc chain) behandelt hoe hetzelfde principe van toepassing is op de rest van het pakket
Status 'opgelost', tijdstempels en auteursidentiteit
Drie attributen dragen de revisiesemantiek, en alle drie zijn ze schrijfbaar op de geretourneerde objecten. Done is gekoppeld aan het attribuut done — Excel toont een opgeloste thread ingeklapt met een link 'Opnieuw openen'. DateTime is het ISO-8601 UTC-aanmaaktijdstempel (dT); HotXLS vervangt dit door een vaste tijdelijke aanduiding wanneer u dit leeg laat, zodat het onderdeel altijd valideert, maar een echt tijdstempel maakt de geschiedenis van de thread leesbaar, dus stel dit in. Aan de identiteitskant stelt elke TXLSXPerson de ProviderId beschikbaar — doorgaans None voor lokaal geschreven vermeldingen — en een UserId die u kunt vullen met een UPN of e-mailadres wanneer uw applicatie dit weet:
var
Root: TXLSXThreadedComment;
Person: TXLSXPerson;
begin
Root := Sheet.ThreadedComments.FindAt('D9');
if Root <> nil then
Root.Done := True; // opgeslagen als done="1"; Excel toont de thread als opgelost
Person := Book.Persons.FindByDisplayName('Maria Ortiz');
if Person <> nil then
Person.UserId := 'maria.ortiz@example.com';
end;
Eén grens om duidelijk te stellen: HotXLS schrijft het <mentions>-element leeg. @-vermeldingsrecords — het mechanisme dat de naam van een collega in de opmerkingstekst markeert en een melding in Microsoft 365 activeert — worden niet gemodelleerd, dus tekst die een @-teken bevat wordt opgeslagen als platte tekst. Voor een gegenereerd revisiewerkboek is dat zelden een gemis, maar als uw workflow afhankelijk is van meldingen van vermeldingen, plan dan dat een mens deze toevoegt in Excel. De auteursidentiteit in het person-onderdeel sluit natuurlijk aan bij de werkboekniveau-herkomstvelden die worden behandeld in werkboekmetadata en documenteigenschappen, waar de rest van het audittraject van een gegenereerd bestand zich bevindt
Wat doen oudere Excel-versies met threaded comments?
Excel 2016 en eerder dateren van vóór het threaded model, en ze negeren simpelweg onderdelen die ze niet begrijpen. Wanneer Excel 365 zelf een threaded conversatie opslaat, schrijft het ook een legacy opmerkingenschaduw — een tijdelijke notitie met de tekst "[Threaded comment]…" — juist zodat oudere versies iets tonen bij de verankerde cel. HotXLS genereert alleen de threaded onderdelen, zonder legacy-schaduw, dus een bestand dat door uw code is geschreven, toont helemaal geen opmerkingindicatie wanneer het in Excel 2016 wordt geopend. Als uw doelgroep pre-365-installaties omvat en de annotatie daar zichtbaar moet zijn, blijft de legacy AddComment-API het compatibele kanaal; vermijd gewoon om beide modellen op dezelfde cel te stapelen zonder elke Excel-versie te testen waarnaar u verzendt, want hoe een lezer een notitie en een thread op één cel met elkaar verzoent, is de beslissing van de lezer, niet de uwe
De andere harde grens is het bestandsformaat zelf. Threaded comments zijn een OOXML-structuur zonder BIFF8-tegenhanger, dus de .xls-kant van HotXLS heeft geen threaded API — een werkboek dat in het verouderde binaire formaat moet blijven is beperkt tot klassieke notities. In de praktijk is de beslissingstabel kort: schrijft u .xlsx voor Excel 365 of web/mobiele Excel-lezers, gebruik dan AddThreadedComment en krijg echte conversaties; richt u zich op Excel 2016 of .xls, gebruik dan AddComment en accepteer het notitiemodel; controleert u een bestand dat u hebt ontvangen, controleer dan zowel ThreadedComments als Comments, want een werkboek dat in beide werelden heeft geleefd kan legitiem beide bevatten. De volledige API-oppervlakte voor beide generaties is gedocumenteerd op de productpagina van het HotXLS Delphi Excel Component