|
| 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 | +} |
0 commit comments