Ha Delphiből generál egy munkafüzetet, és a klasszikus megjegyzés (comment) API-val lát el egy cellát megjegyzéssel, az Excel 365 a szöveget a Jegyzetek (Notes) alá helyezi el: egy régi stílusú sárga dobozba, amelyben nincs Válasz (Reply) mező, szerzői profilkép és lezárás (resolve) gomb. A HotXLS valódi Excel 365 egymásba ágyazott megjegyzéseket (threaded comments) ír az XLSX motoron keresztül az AddThreadedComment és az AddThreadedReply metódusokkal, kibocsátva a dedikált xl/threadedComments/threadedCommentN.xml részt laponként, és regisztrálva minden szerzőt a munkafüzet-szintű személy (person) részben, így az Ön kódja által írt beszélgetés ugyanaz az objektum lesz, amelyre a felülvizsgáló válaszol az Excelben.
A különbségtétel azért fontos, mert a két funkció csak hasonlít egymásra. A jegyzet (note) egy lebegő szövegdoboz; a szálankénti megjegyzés (threaded comment) pedig egy stabil azonosítókkal, válaszfával, szerzői nyilvántartással és egy lezártsági (resolved) jelzővel ellátott beszélgetési rekord — vagyis mindazon dolgok, amelyeken a felülvizsgálati munkafolyamat valójában alapul. Ez a cikk először az OOXML struktúrát mutatja be, mert ha egyszer egymás mellett látja a két tárolási modellt, az Excelben tapasztalható minden viselkedésbeli különbség megszűnik rejtélyesnek lenni.
Miért jelennek meg a megjegyzéseim jegyzetként az Excel 365-ben?
A rövid válasz: a megjegyzések két generációja osztozik egyetlen rácson, és teljesen különböző részekben élnek a csomagon belül. A hagyományos modell — amelyet az AddComment céloz meg — a szöveget az xl/comments1.xml fájlban tárolja (tartalomtípus: application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) and positions the balloon through a companion VML drawing part, xl/drawings/vmlDrawing1.vml. Ez a páros megelőzi a szalagot; az Excel 365 továbbra is hűségesen olvassa, de az eredményt 'jegyzetként' rendereli, és nem kínál hozzá szálkezelési felületet, mivel a tárolóban nincs semmi, amit szálba lehetne fűzni. A szerző egy megjelenítendő karakterlánc, a pozíció egy VML alakzat, és ez a teljes modell.
Az Excel 365-tel bevezetett egymásba ágyazott megjegyzések (threaded comments) teljesen figyelmen kívül hagyják a VML réteget. Minden beszélgetést tartalmazó lap saját xl/threadedComments/threadedCommentN.xml részt hordoz az application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml tartalomtípus alatt, a munkafüzet pedig egyetlen xl/person/person.xml részt tartalmaz (tartalomtípus: ...spreadsheetml.people+xml), amely minden résztvevőt egyszer listáz. A HotXLS mindkét modellt elérhetővé teszi ugyanazon a munkalapon: az AddComment továbbra is a hagyományos párost írja, míg az AddThreadedComment az új részeket. Ha a kimenete jegyzetként jelenik meg, akkor az első API-t hívta meg, pedig a másodikat szerette volna. A hagyományos modell továbbra is a megfelelő eszköz bizonyos feladatokhoz — a korábbi, a cellamegjegyzésekről és hiperhivatkozásokról a felülvizsgálati munkafolyamatokban szóló cikk részletesen foglalkozik vele, beleértve az XLS oldalt is —, de abból semmi sem fejleszthető szállá.
Mit ír a HotXLS a csomagba?
A HotXLS minden választ TXLSXThreadedComment objektumként modellez, amely tartalmaz egy cellahorgonyt (Ref), egy GUID-stílusú azonosítót (Id), egy opcionális ParentId-t, egy a személyek listáján keresztül feloldható AuthorId-t, egy DisplayName tükrözést, a szövegtörzset, egy Done (kész) jelzőt és egy ISO-8601-es DateTime-ot. Mentéskor minden bejegyzés <threadedComment> elemmé válik, amelynek t attribútuma az azonosítót hordozza, a dT attribútuma az időbélyeget, a parentT attribútuma pedig — amely csak a gyermekválaszoknál van jelen — a szülőazonosítót nevezi meg. Az Excel a parentT és a t egyeztetésével építi fel újra a beszélgetési fát; az XML-ben nincs egymásba ágyazás, csak egy egyszerű lista és hivatkozások.
A személy (person) rész az a darab, amelyet a legtöbb kézzel írt implementáció elfelejt. Egy egymásba ágyazott megjegyzésben minden authorId-nak fel kell oldódnia egy <person> bejegyzésre az xl/person/person.xml-ben, amely be van kötve a munkafüzet kapcsolataiba, saját tartalomtípus-felülírással — különben az Excelnek nincs megjelenítendő neve, amit mutathatna. A HotXLS automatikusan kezeli a regisztrációt: az AddThreadedComment megkeresi a szerzőt a munkafüzet Persons listáján a megjelenített név alapján, és ha nem létezik, létrehoz egy bejegyzést egy új GUID-dal, így az ugyanazon szerző által írt egymást követő megjegyzések közös identitáson osztoznak. A munkalapkapcsolatok megkapják a threadedComments kapcsolatot, a munkafüzetkapcsolatok a person kapcsolatot, a tartalomtípusok jegyzéke pedig mindkét felülírást megkapja, anélkül, hogy ebből bármi is megjelenne a kódjában.
Válaszlánc felépítése az AddThreadedComment és az AddThreadedReply segítségével
Az AddThreadedComment létrehozza a beszélgetés gyökerét: a ParentId-ja üresen marad, ez jelöli a szál tetejét. Az AddThreadedReply egy ParentRef paramétert vesz át — a cellahivatkozást, ahol a gyökér él —, megtalálja a gyökeret ennél a horgonynál, és a gyökér Id-jával pecsételi meg az új válasz ParentId-ját. Mindkettő visszaadja az új TXLSXThreadedComment-et, így beállíthatja az időbélyeget vagy a lezárt állapotot a frissen létrehozott objektumon:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Root: TXLSXThreadedComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('forecast.xlsx');
Sheet := Book.Sheets[0];
// Beszélgetés gyökere; a ParentId üres marad
Root := Sheet.AddThreadedComment(8, 3,
'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
Root.DateTime := '2026-07-06T09:12:00Z';
// A válaszok ugyanahhoz a cellához kapcsolódnak; a ParentRef a gyökércellát nevezi meg
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;
Két részletre érdemes figyelni ebben a listában. Elsőként, a Root.Ref kerül átadásra ahelyett, hogy kézzel épített karakterláncot használnánk: a könyvtár által generált hivatkozás garantáltan megegyezik azzal, amit az AddThreadedReply keresni fog, ami kiküszöböli a hibás cellacímzésekből eredő hibák egész osztályát. Másodszor, mindkét szerzőt egyszerű megjelenítendő névként adtuk át — a személyek nyilvántartása, a GUID identitások és az authorId bekötések mind a hívások mögött történtek. Nyissa meg a mentett fájlt az Excel 365-ben, és a cellahorgonyzás, a válaszok sorrendje, valamint a két különböző résztvevő mind élőben látható: kattintson a Válasz gombra, és az Excel hozzáfűzi a választ ugyanahhoz a szálhoz, amelyet a kódja indított el.
Beszélgetés visszaolvasása: oda-vissza út viselkedés
A HotXLS a 2.122.0-s verziótól kezdődően biztosítja a szálankénti megjegyzések oda-vissza útját: egy mentett csomag újbóli megnyitása újjáépíti minden lap beszélgetési listáját és a munkafüzet résztvevői listáját a részekből, így az azonosítók, válaszhivatkozások és megjelenített nevek túlélik a teljes olvasás→írás ciklust. Az olvasó a person.xml fájlt minden lap tartalom előtt elemzi, ami lehetővé teszi, hogy minden authorId megjelenített névvé oldódjon fel betöltéskor; az elemzett személyazonosítók eredeti formájukban megőrződnek ahelyett, hogy újragenerálnák őket, így a kódja és az Excel között ingázó munkafüzet tetszőlegesen sok oda-vissza út során is megőrzi a stabil szerzői identitásokat.
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;
A lapos lista és hivatkozások tárolása itt szándékosan átlátszik: a ThreadedComments a válaszokat a részek sorrendjében sorolja fel, és a szülőazonosító (ParentId) hiánya azonosítja az egyes gyökereket. Ha a fa szerkezetre van szüksége — például egy felülvizsgálati napló exportálásához —, először csoportosítson a Ref alapján, majd láncolja a ParentId-t az Id-hoz az egyes cellák csoportjain belül. Ez a 'megőrizzük azt, amit elemeztünk' viselkedés a könyvtár tágabb irányelvének egyik példája; a témák, a kiterjesztési listák és a számítási lánc veszteségmentes oda-vissza útjáról szóló cikk bemutatja, hogyan érvényesül ugyanez az elv a csomag többi részében is.
Lezárt állapot, időbélyegek és a szerző kiléte
Három attribútum hordozza a felülvizsgálati szemantikát, és mindhárom írható a visszaadott objektumokon. A Done megfelel a done attribútumnak — az Excel a lezárt szálat összecsukva mutatja egy Újbóli megnyitás (Reopen) linkkel. A DateTime az ISO-8601 UTC létrehozási bélyegző (dT); a HotXLS egy rögzített helyőrzővel helyettesíti, ha üresen hagyja, hogy a rész mindig érvényes legyen, de a valódi időbélyeg az, ami olvashatóvá teszi a szál történetét, ezért érdemes beállítani. Az identitás oldalán minden TXLSXPerson elérhetővé tesz egy ProviderId-t — ez jellemzően None a helyileg létrehozott bejegyzéseknél — és egy UserId-t, amelyet UPN-nel vagy e-mail címmel tölthet ki, ha az alkalmazása ismeri azt:
var
Root: TXLSXThreadedComment;
Person: TXLSXPerson;
begin
Root := Sheet.ThreadedComments.FindAt('D9');
if Root <> nil then
Root.Done := True; // mentve mint done="1"; az Excel a szálat lezártként mutatja
Person := Book.Persons.FindByDisplayName('Maria Ortiz');
if Person <> nil then
Person.UserId := 'maria.ortiz@example.com';
end;
Egy határt egyértelműen meg kell említeni: a HotXLS üresen írja be a <mentions> elemet. A @-említés rekordok — az a gépezet, amely megvilágítja a kolléga nevét a megjegyzés szövegében, és értesítést vált ki a Microsoft 365-ben — nincsenek modellezve, így a @ jelet tartalmazó szöveg egyszerű szövegként kerül tárolásra. Egy generált felülvizsgálati munkafüzetnél ez ritkán jelent veszteséget, de ha a munkafolyamata az említési értesítésektől függ, tervezze meg, hogy azokat egy ember adja hozzá az Excelben. A személy részben található szerzői identitás természetes módon párosul a munkafüzet-szintű eredetmezőkkel, amelyekkel a munkafüzet-metaadatokról és dokumentumtulajdonságokról szóló cikk foglalkozik, ahol a generált fájlok ellenőrzési nyomvonalának többi része található.
Mit tesznek a régebbi Excel verziók az egymásba ágyazott megjegyzésekkel?
Az Excel 2016 és a korábbi verziók megelőzik az egymásba ágyazott modellt, és egyszerűen figyelmen kívül hagyják azokat a részeket, amelyeket nem értenek. Amikor maga az Excel 365 ment el egy egymásba ágyazott beszélgetést, egy hagyományos megjegyzésárnyékot is ír — egy '[Threaded comment]...' szövegű helyőrző jegyzetet —, pontosan azért, hogy a régebbi verziók mutassanak valamit a rögzített cellánál. A HotXLS csak a szálankénti részeket bocsát ki, a hagyományos árnyék nélkül, így az Ön kódja által írt fájl egyáltalán nem mutat megjegyzésjelzőt az Excel 2016-ban való megnyitáskor. Ha a célközönsége 365 előtti telepítéseket is tartalmaz, és a megjegyzésnek ott is láthatónak kell lennie, a hagyományos AddComment API marad a kompatibilis csatorna; kerülje el a két modell halmozását ugyanazon a cellán anélkül, hogy tesztelné az összes kiszállított Excel verziót, mert az, hogy az olvasó hogyan egyezteti össze a jegyzetet és a szálat egy cellán, az olvasó döntése, nem az öné.
A másik szigorú határ maga a fájlformátum. Az egymásba ágyazott megjegyzések egy OOXML struktúra, amelynek nincs BIFF8 megfelelője, így a HotXLS .xls oldalán nincs szálkezelési API — a hagyományos bináris formátumban maradó munkafüzet a klasszikus jegyzetekre korlátozódik. A gyakorlatban a döntési táblázat rövid: ha .xlsx-et ír Excel 365-höz vagy webes/mobil Excel olvasókhoz, használja az AddThreadedComment-et a valódi beszélgetésekhez; ha az Excel 2016-ot vagy az .xls-t célozza meg, használja az AddComment-et és fogadja el a jegyzet modellt; ha egy kapott fájlt ellenőriz, ellenőrizze mind a ThreadedComments-et, mind a Comments-et, mert egy mindkét világban élt munkafüzet jogosan hordozhatja mindkettőt. Mindkét generáció teljes API felülete dokumentálva van a HotXLS Delphi Excel komponens termékoldalán.