Skip to content

Commit 1540e32

Browse files
authored
add threaded comment example (#1180)
* Add threaded comment example
1 parent 76d81ca commit 1540e32

File tree

4 files changed

+410
-8
lines changed

4 files changed

+410
-8
lines changed

Open-XML-SDK.sln

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentTaskSample", "sampl
7777
EndProject
7878
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AddNamedSheetView", "samples\NamedSheetView\AddNamedSheetView.csproj", "{F48B7D50-16CB-4BEF-A614-2DED9960AF09}"
7979
EndProject
80-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SVGExample", "samples\SVGExample\SVGExample.csproj", "{7CFCA307-F221-4FC9-A531-6CAC503E1FFB}"
81-
EndProject
8280
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentFormat.OpenXml.Generator.Models", "gen\DocumentFormat.OpenXml.Generator.Models\DocumentFormat.OpenXml.Generator.Models.csproj", "{C91489AB-FF14-4FAD-BA51-35371ADD7E1C}"
8381
EndProject
82+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThreadedCommentExample", "samples\ThreadedCommentExample\ThreadedCommentExample.csproj", "{5241BCF2-331D-428E-A9C4-F8DF92C8F726}"
83+
EndProject
8484
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerPointModernCommentSample", "samples\PowerPointModernCommentSample\PowerPointModernCommentSample.csproj", "{3ECC7570-3501-479D-9CD9-64799C2AD149}"
8585
EndProject
86+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SVGExample", "samples\SVGExample\SVGExample.csproj", "{BADAC0CC-F3E6-440E-B322-DA2B97625F26}"
87+
EndProject
8688
Global
8789
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8890
Debug|Any CPU = Debug|Any CPU
@@ -165,18 +167,22 @@ Global
165167
{F48B7D50-16CB-4BEF-A614-2DED9960AF09}.Debug|Any CPU.Build.0 = Debug|Any CPU
166168
{F48B7D50-16CB-4BEF-A614-2DED9960AF09}.Release|Any CPU.ActiveCfg = Release|Any CPU
167169
{F48B7D50-16CB-4BEF-A614-2DED9960AF09}.Release|Any CPU.Build.0 = Release|Any CPU
168-
{7CFCA307-F221-4FC9-A531-6CAC503E1FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
169-
{7CFCA307-F221-4FC9-A531-6CAC503E1FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
170-
{7CFCA307-F221-4FC9-A531-6CAC503E1FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
171-
{7CFCA307-F221-4FC9-A531-6CAC503E1FFB}.Release|Any CPU.Build.0 = Release|Any CPU
172170
{C91489AB-FF14-4FAD-BA51-35371ADD7E1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
173171
{C91489AB-FF14-4FAD-BA51-35371ADD7E1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
174172
{C91489AB-FF14-4FAD-BA51-35371ADD7E1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
175173
{C91489AB-FF14-4FAD-BA51-35371ADD7E1C}.Release|Any CPU.Build.0 = Release|Any CPU
174+
{5241BCF2-331D-428E-A9C4-F8DF92C8F726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
175+
{5241BCF2-331D-428E-A9C4-F8DF92C8F726}.Debug|Any CPU.Build.0 = Debug|Any CPU
176+
{5241BCF2-331D-428E-A9C4-F8DF92C8F726}.Release|Any CPU.ActiveCfg = Release|Any CPU
177+
{5241BCF2-331D-428E-A9C4-F8DF92C8F726}.Release|Any CPU.Build.0 = Release|Any CPU
176178
{3ECC7570-3501-479D-9CD9-64799C2AD149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
177179
{3ECC7570-3501-479D-9CD9-64799C2AD149}.Debug|Any CPU.Build.0 = Debug|Any CPU
178180
{3ECC7570-3501-479D-9CD9-64799C2AD149}.Release|Any CPU.ActiveCfg = Release|Any CPU
179181
{3ECC7570-3501-479D-9CD9-64799C2AD149}.Release|Any CPU.Build.0 = Release|Any CPU
182+
{BADAC0CC-F3E6-440E-B322-DA2B97625F26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
183+
{BADAC0CC-F3E6-440E-B322-DA2B97625F26}.Debug|Any CPU.Build.0 = Debug|Any CPU
184+
{BADAC0CC-F3E6-440E-B322-DA2B97625F26}.Release|Any CPU.ActiveCfg = Release|Any CPU
185+
{BADAC0CC-F3E6-440E-B322-DA2B97625F26}.Release|Any CPU.Build.0 = Release|Any CPU
180186
EndGlobalSection
181187
GlobalSection(SolutionProperties) = preSolution
182188
HideSolutionNode = FALSE
@@ -202,9 +208,10 @@ Global
202208
{890B74DD-6316-4D56-B42A-5D66F10F88C6} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
203209
{5DE9FB8F-A7C2-4038-A4A8-1622CDB6821A} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
204210
{F48B7D50-16CB-4BEF-A614-2DED9960AF09} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
205-
{7CFCA307-F221-4FC9-A531-6CAC503E1FFB} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
206211
{C91489AB-FF14-4FAD-BA51-35371ADD7E1C} = {3653266D-2C88-4487-8977-839CB3E78A0A}
212+
{5241BCF2-331D-428E-A9C4-F8DF92C8F726} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
207213
{3ECC7570-3501-479D-9CD9-64799C2AD149} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
214+
{BADAC0CC-F3E6-440E-B322-DA2B97625F26} = {7DAF7304-40CC-4180-88A5-9A89DD13C565}
208215
EndGlobalSection
209216
GlobalSection(ExtensibilityGlobals) = postSolution
210217
SolutionGuid = {6F476383-E917-43D1-A1E5-9A61A47DA3F5}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
#nullable enable
4+
5+
using Common;
6+
using DocumentFormat.OpenXml.Office2019.Excel.ThreadedComments;
7+
using DocumentFormat.OpenXml.Packaging;
8+
9+
// WORKBOOK
10+
using DocumentFormat.OpenXml.Spreadsheet;
11+
using System;
12+
using System.IO;
13+
14+
namespace ThreadedCommentsExample
15+
{
16+
internal class Program
17+
{
18+
private static void Main(string[] args)
19+
{
20+
string sheetName = "commentSheet";
21+
22+
string column = "A";
23+
24+
uint row = 1;
25+
26+
string reference = string.Concat(column, row.ToString());
27+
28+
int nRequiredArgs = 1;
29+
30+
// Must have x arguments.
31+
if (args.Length < nRequiredArgs)
32+
{
33+
ExampleUtilities.ShowHelp(new string[] { $"ThreadedCommentExample requires {nRequiredArgs} arguments." });
34+
return;
35+
}
36+
37+
string filePath = args[0];
38+
39+
// start fresh with each run
40+
if (ExampleUtilities.FileCheck(filePath))
41+
{
42+
try
43+
{
44+
File.Delete(filePath);
45+
}
46+
catch (Exception e)
47+
{
48+
Console.WriteLine(e.Message);
49+
return;
50+
}
51+
}
52+
53+
// WORKBOOK
54+
SpreadsheetDocument? sd = ExampleUtilities.CreateSpreadsheetWorkbook(filePath, sheetName);
55+
56+
if (sd != null)
57+
{
58+
ExampleUtilities.InsertText((SpreadsheetDocument)sd, sheetName, @"Please comment on this cell.", column, row);
59+
}
60+
61+
if (!(sd is null))
62+
{
63+
CreateMiscellaneousParts(sd, sheetName);
64+
65+
Worksheet? worksheet = ExampleUtilities.GetSheet(sd, sheetName)?.Worksheet;
66+
67+
if (worksheet != null)
68+
{
69+
worksheet.AddChild(new LegacyDrawing() { Id = "rId1" });
70+
71+
// NOTE: UserId, DisplayName, Id and ProviderId should be generated by querying the identity server used by this org and account.
72+
string displayNameUser = "Jose Contoso";
73+
string idUser = string.Concat("{", System.Guid.NewGuid().ToString().ToUpper(), "}");
74+
string tcId = string.Concat("{", System.Guid.NewGuid().ToString().ToUpper(), "}");
75+
76+
// For the format of these userId parameter, please refer to [MS-XLSX] 2.6.203 CT_Person
77+
// This can be a SID from an Active Directory provider, an email address using "PeoplePicker", and O365 id or a simple name.
78+
string userIdJose = "[email protected]";
79+
string providerIdAzure = "PeoplePicker";
80+
81+
WorkbookPart workbookPart = sd.WorkbookPart ?? sd.AddWorkbookPart();
82+
83+
WorkbookPersonPart pp = workbookPart.AddNewPart<WorkbookPersonPart>();
84+
85+
pp.PersonList = new PersonList(new Person() { DisplayName = displayNameUser, Id = idUser, UserId = userIdJose, ProviderId = providerIdAzure });
86+
87+
WorksheetPart wsp = ExampleUtilities.GetSheet(sd, sheetName);
88+
89+
WorksheetCommentsPart wscp = wsp.AddNewPart<WorksheetCommentsPart>();
90+
wscp.Comments = new Comments(
91+
new Authors(
92+
new Author("tc=" + tcId)), new CommentList(
93+
new Comment(
94+
new DocumentFormat.OpenXml.Spreadsheet.CommentText(
95+
new DocumentFormat.OpenXml.Spreadsheet.Text("Comment: Ok, here's a comment!")))
96+
97+
// Comment attributes
98+
{ Reference = reference, AuthorId = 0, ShapeId = 0, Guid = tcId }));
99+
100+
WorksheetThreadedCommentsPart wstcp = wsp.AddNewPart<WorksheetThreadedCommentsPart>();
101+
wstcp.ThreadedComments = new ThreadedComments(
102+
new ThreadedComment(
103+
new ThreadedCommentText("Ok, here's a threaded comment!"))
104+
105+
// ThreadedComment attributes
106+
{ Ref = reference, PersonId = idUser, Id = tcId, DT = System.DateTime.Now });
107+
}
108+
109+
// Close the document.
110+
sd.Close();
111+
}
112+
else
113+
{
114+
throw new Exception("SpreadsheetDocument is null");
115+
}
116+
}
117+
118+
private static void CreateMiscellaneousParts(SpreadsheetDocument? sd, string sheetName)
119+
{
120+
if (sd == null)
121+
{
122+
return;
123+
}
124+
125+
CoreFilePropertiesPart cfp = sd.AddCoreFilePropertiesPart();
126+
using (System.Xml.XmlTextWriter writer =
127+
new System.Xml.XmlTextWriter(cfp.GetStream(FileMode.Create), System.Text.Encoding.UTF8))
128+
{
129+
writer.WriteRaw("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?> <cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <cp:lastModifiedBy>Jose Contose</cp:lastModifiedBy> <dcterms:modified xsi:type=\"dcterms:W3CDTF\">2022-03-01T18:55:39Z</dcterms:modified> </cp:coreProperties>");
130+
writer.Flush();
131+
}
132+
133+
ExtendedFilePropertiesPart efp = sd.AddExtendedFilePropertiesPart();
134+
using (System.Xml.XmlTextWriter writer =
135+
new System.Xml.XmlTextWriter(efp.GetStream(FileMode.Create), System.Text.Encoding.UTF8))
136+
{
137+
writer.WriteRaw("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?> <Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\"> <Application>Microsoft Excel</Application> <DocSecurity>0</DocSecurity> <ScaleCrop>false</ScaleCrop> <HeadingPairs> <vt:vector size=\"2\" baseType=\"variant\"> <vt:variant> <vt:lpstr>Worksheets</vt:lpstr> </vt:variant> <vt:variant> <vt:i4>1</vt:i4> </vt:variant> </vt:vector> </HeadingPairs> <TitlesOfParts> <vt:vector size=\"1\" baseType=\"lpstr\"> <vt:lpstr>commentSheet</vt:lpstr> </vt:vector> </TitlesOfParts> <LinksUpToDate>false</LinksUpToDate> <SharedDoc>false</SharedDoc> <HyperlinksChanged>false</HyperlinksChanged> <AppVersion>16.0300</AppVersion> </Properties>");
138+
writer.Flush();
139+
}
140+
141+
LabelInfoPart lip = sd.AddLabelInfoPart();
142+
lip.ClassificationLabelList = new DocumentFormat.OpenXml.Office2021.MipLabelMetaData.ClassificationLabelList(
143+
new DocumentFormat.OpenXml.Office2021.MipLabelMetaData.ClassificationLabel()
144+
{
145+
Id = "{f42aa342-8706-4288-bd11-ebb85995028c}", // Unique sensitivity label Id.
146+
SiteId = "{72f988bf-86f1-41af-91ab-2d7cd011db47}", // Azure AD site Id.
147+
Method = "Standard",
148+
Enabled = true,
149+
ContentBits = 0,
150+
Removed = false,
151+
});
152+
153+
VmlDrawingPart wsd = ExampleUtilities.GetSheet(sd, sheetName).AddNewPart<VmlDrawingPart>("rId1");
154+
using (System.Xml.XmlTextWriter writer =
155+
new System.Xml.XmlTextWriter(wsd.GetStream(FileMode.Create), System.Text.Encoding.UTF8))
156+
{
157+
writer.WriteRaw("<xml xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\"> <o:shapelayout v:ext=\"edit\"> <o:idmap v:ext=\"edit\" data=\"1\"/> </o:shapelayout><v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\" path=\"m,l,21600r21600,l21600,xe\"> <v:stroke joinstyle=\"miter\"/> <v:path gradientshapeok=\"t\" o:connecttype=\"rect\"/> </v:shapetype><v:shape id=\"_x0000_s1025\" type=\"#_x0000_t202\" style='position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1; visibility:hidden' fillcolor=\"infoBackground [80]\" strokecolor=\"none [81]\" o:insetmode=\"auto\"> <v:fill color2=\"infoBackground [80]\"/> <v:shadow color=\"none [81]\" obscured=\"t\"/> <v:path o:connecttype=\"none\"/> <v:textbox style='mso-direction-alt:auto'> <div style='text-align:left'></div> </v:textbox> <x:ClientData ObjectType=\"Note\"> <x:MoveWithCells/> <x:SizeWithCells/> <x:Anchor> 1, 15, 0, 2, 3, 31, 4, 1</x:Anchor> <x:AutoFill>False</x:AutoFill> <x:Row>0</x:Row> <x:Column>0</x:Column> </x:ClientData> </v:shape></xml>");
158+
writer.Flush();
159+
}
160+
}
161+
}
162+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<Project Sdk="Microsoft.NET.Sdk"></Project>

0 commit comments

Comments
 (0)