From 455e7761f002316b32295a4756a0c3e005d1f240 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 5 Feb 2024 11:57:56 -0800 Subject: [PATCH 01/53] closes #231 --- ...-add-text-to-a-word-processing-document.md | 105 ++++++------------ .../word/open_and_add_text_to/cs/Program.cs | 20 +++- .../word/open_and_add_text_to/vb/Program.vb | 36 +++++- 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/docs/word/how-to-open-and-add-text-to-a-word-processing-document.md b/docs/word/how-to-open-and-add-text-to-a-word-processing-document.md index b18ef6dd..a14babce 100644 --- a/docs/word/how-to-open-and-add-text-to-a-word-processing-document.md +++ b/docs/word/how-to-open-and-add-text-to-a-word-processing-document.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 02/05/2024 ms.localizationpriority: high --- # Open and add text to a word processing document @@ -24,66 +24,51 @@ document. -------------------------------------------------------------------------------- ## How to Open and Add Text to a Document + The Open XML SDK helps you create Word processing document structure -and content using strongly-typed classes that correspond to **WordprocessingML** elements. This topic shows how +and content using strongly-typed classes that correspond to `WordprocessingML` elements. This topic shows how to use the classes in the Open XML SDK to open a Word processing document and add text to it. In addition, this topic introduces the -basic document structure of a **WordprocessingML** document, the associated XML +basic document structure of a `WordprocessingML` document, the associated XML elements, and their corresponding Open XML SDK classes. -------------------------------------------------------------------------------- ## Create a WordprocessingDocument Object + In the Open XML SDK, the class represents a Word document package. To open and work with a Word document, create an instance of the class from the document. When you create the instance from the document, you can then obtain access to the main document part that contains the text of the document. The text in the main document part is represented -in the package as XML using **WordprocessingML** markup. +in the package as XML using `WordprocessingML` markup. -To create the class instance from the document you call one of the **Open** methods. Several are provided, each with a -different signature. The sample code in this topic uses the [Open(String, Boolean)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method with a -signature that requires two parameters. The first parameter takes a full +To create the class instance from the document you call one of the `Open` methods. Several are provided, each with a +different signature. The sample code in this topic uses the method with a signature that requires two parameters. The first parameter takes a full path string that represents the document to open. The second parameter -is either **true** or **false** and represents whether you want the file to +is either `true` or `false` and represents whether you want the file to be opened for editing. Changes you make to the document will not be -saved if this parameter is **false**. +saved if this parameter is `false`. -The following code example calls the **Open** -method. +The following code example calls the `Open` method. ### [C#](#tab/cs-0) -```csharp - // Open a WordprocessingDocument for editing using the filepath. - WordprocessingDocument wordprocessingDocument = - WordprocessingDocument.Open(filepath, true); -``` - +[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - ' Open a WordprocessingDocument for editing using the filepath. - Dim wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) -``` +[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb#snippet1)] *** When you have opened the Word document package, you can add text to the -main document part. To access the body of the main document part, assign -a reference to the existing document body, as shown in the following -code example. +main document part. To access the body of the main document part, create +any missing elements and assign a reference to the document body, +as shown in the following code example. ### [C#](#tab/cs-1) -```csharp - // Assign a reference to the existing document body. - Body body = wordprocessingDocument.MainDocumentPart.Document.Body; -``` - +[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - ' Assign a reference to the existing document body. - Dim body As Body = wordprocessingDocument.MainDocumentPart.Document.Body -``` +[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb#snippet2)] *** @@ -94,66 +79,46 @@ code example. -------------------------------------------------------------------------------- ## Generate the WordprocessingML Markup to Add the Text When you have access to the body of the main document part, add text by -adding instances of the **Paragraph**, **Run**, and **Text** -classes. This generates the required WordprocessingML markup. The -following code example adds the paragraph, run and text. +adding instances of the , , +and classes. +This generates the required WordprocessingML markup. The +following code example adds the paragraph. ### [C#](#tab/cs-2) -```csharp - // Add new text. - Paragraph para = body.AppendChild(new Paragraph()); - Run run = para.AppendChild(new Run()); - run.AppendChild(new Text(txt)); -``` - +[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Add new text. - Dim para As Paragraph = body.AppendChild(New Paragraph()) - Dim run As Run = para.AppendChild(New Run()) - run.AppendChild(New Text(txt)) -``` + +[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb#snippet3)] *** -------------------------------------------------------------------------------- ## Sample Code -The example **OpenAndAddTextToWordDocument** +The example `OpenAndAddTextToWordDocument` method shown here can be used to open a Word document and append some text using the Open XML SDK. To call this method, pass a full path -filename as the first parameter and the text to add as the second. For -example, the following code example opens the Letter.docx file in the -Public Documents folder and adds text to it. +filename as the first parameter and the text to add as the second. ### [C#](#tab/cs-3) -```csharp - string strDoc = @"C:\Users\Public\Documents\Letter.docx"; - string strTxt = "Append text in body - OpenAndAddTextToWordDocument"; - OpenAndAddTextToWordDocument(strDoc, strTxt); -``` - +[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - Dim strDoc As String = "C:\Users\Public\Documents\Letter.docx" - Dim strTxt As String = "Append text in body - OpenAndAddTextToWordDocument" - OpenAndAddTextToWordDocument(strDoc, strTxt) -``` +[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb#snippet4)] *** Following is the complete sample code in both C\# and Visual Basic. -Notice that the **OpenAndAddTextToWordDocument** method does not -include an explicit call to **Save**. That is +Notice that the `OpenAndAddTextToWordDocument` method does not +include an explicit call to `Save`. That is because the AutoSave feature is on by default and has not been disabled -in the call to the **Open** method through use -of **OpenSettings**. +in the call to the `Open` method through use +of `OpenSettings`. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs)] +[!code-csharp[](../../samples/word/open_and_add_text_to/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb)] +[!code-vb[](../../samples/word/open_and_add_text_to/vb/Program.vb#snippet0)] -------------------------------------------------------------------------------- ## See also diff --git a/samples/word/open_and_add_text_to/cs/Program.cs b/samples/word/open_and_add_text_to/cs/Program.cs index 007cef97..bd6e85d8 100644 --- a/samples/word/open_and_add_text_to/cs/Program.cs +++ b/samples/word/open_and_add_text_to/cs/Program.cs @@ -1,12 +1,11 @@ - +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; -OpenAndAddTextToWordDocument(args[0], args[1]); - static void OpenAndAddTextToWordDocument(string filepath, string txt) { + // // Open a WordprocessingDocument for editing using the filepath. WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filepath, true); @@ -14,18 +13,31 @@ static void OpenAndAddTextToWordDocument(string filepath, string txt) { throw new ArgumentNullException(nameof(wordprocessingDocument)); } + // + // // Assign a reference to the existing document body. MainDocumentPart mainDocumentPart = wordprocessingDocument.MainDocumentPart ?? wordprocessingDocument.AddMainDocumentPart(); mainDocumentPart.Document ??= new Document(); mainDocumentPart.Document.Body ??= mainDocumentPart.Document.AppendChild(new Body()); Body body = wordprocessingDocument.MainDocumentPart!.Document!.Body!; + // + // // Add new text. Paragraph para = body.AppendChild(new Paragraph()); Run run = para.AppendChild(new Run()); run.AppendChild(new Text(txt)); + // - // Dispose the handle explicitly. + // There is no using block, so Dispose the handle explicitly. wordprocessingDocument.Dispose(); } +// + +// +string file = args[0]; +string txt = args[1]; + +OpenAndAddTextToWordDocument(args[0], args[1]); +// diff --git a/samples/word/open_and_add_text_to/vb/Program.vb b/samples/word/open_and_add_text_to/vb/Program.vb index 747a60f8..d8dc105f 100644 --- a/samples/word/open_and_add_text_to/vb/Program.vb +++ b/samples/word/open_and_add_text_to/vb/Program.vb @@ -1,3 +1,4 @@ +' Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing @@ -5,22 +6,49 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module MyModule Sub Main(args As String()) + ' + Dim file As String = args(0) + Dim txt As String = args(1) + + OpenAndAddTextToWordDocument(file, txt) + ' End Sub Public Sub OpenAndAddTextToWordDocument(ByVal filepath As String, ByVal txt As String) + + ' ' Open a WordprocessingDocument for editing using the filepath. - Dim wordprocessingDocument As WordprocessingDocument = - WordprocessingDocument.Open(filepath, True) + Dim wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) + + If wordprocessingDocument Is Nothing Then + Throw New ArgumentNullException(NameOf(wordprocessingDocument)) + End If + ' + ' ' Assign a reference to the existing document body. + Dim mainDocumentPart As MainDocumentPart = If(wordprocessingDocument.MainDocumentPart, wordprocessingDocument.AddMainDocumentPart()) + + If wordprocessingDocument.MainDocumentPart.Document Is Nothing Then + wordprocessingDocument.MainDocumentPart.Document = New Document() + End If + + If wordprocessingDocument.MainDocumentPart.Document.Body Is Nothing Then + wordprocessingDocument.MainDocumentPart.Document.Body = New Body() + End If + Dim body As Body = wordprocessingDocument.MainDocumentPart.Document.Body + ' + ' ' Add new text. Dim para As Paragraph = body.AppendChild(New Paragraph) Dim run As Run = para.AppendChild(New Run) run.AppendChild(New Text(txt)) + ' - ' Dispose the handle explicitly. + ' There is not using, so Dispose the handle explicitly. wordprocessingDocument.Dispose() End Sub -End Module \ No newline at end of file +End Module +' From 00a87e65ee6dd97bd8a2e64578c321b7c3692d89 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 5 Feb 2024 13:51:10 -0800 Subject: [PATCH 02/53] closes #230 --- ...-word-processing-document-from-a-stream.md | 87 +++++-------------- samples/word/open_from_a_stream/cs/Program.cs | 21 ++++- samples/word/open_from_a_stream/vb/Program.vb | 31 ++++++- 3 files changed, 72 insertions(+), 67 deletions(-) diff --git a/docs/word/how-to-open-a-word-processing-document-from-a-stream.md b/docs/word/how-to-open-a-word-processing-document-from-a-stream.md index 729c6443..c436959d 100644 --- a/docs/word/how-to-open-a-word-processing-document-from-a-stream.md +++ b/docs/word/how-to-open-a-word-processing-document-from-a-stream.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 02/05/2024 ms.localizationpriority: high --- # Open a word processing document from a stream @@ -47,31 +47,22 @@ XML package contains some number of parts. At a minimum, a method.Several `Open` methods are provided, each with a different +signature. The sample code in this topic uses the `Open` method with a signature that requires two parameters. The first parameter takes a handle to the stream from which -you want to open the document. The second parameter is either **true** or **false** and +you want to open the document. The second parameter is either `true` or `false` and represents whether the stream is opened for editing. -The following code example calls the **Open** +The following code example calls the `Open` method. ### [C#](#tab/cs-0) -```csharp - // Open a WordProcessingDocument based on a stream. - WordprocessingDocument wordprocessingDocument = - WordprocessingDocument.Open(stream, true); -``` - +[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - ' Open a WordProcessingDocument based on a stream. - Dim wordprocessingDocument As WordprocessingDocument = _ - WordprocessingDocument.Open(stream, True) -``` +[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb#snippet1)] *** @@ -81,85 +72,55 @@ method. When you open the Word document package, you can add text to the main document part. To access the body of the main document part you assign a -reference to the existing document body, as shown in the following code -segment. +reference to the document body, as shown in the following code segment. ### [C#](#tab/cs-1) -```csharp - // Assign a reference to the existing document body. - Body body = wordprocessingDocument.MainDocumentPart.Document.Body; -``` - +[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - ' Assign a reference to the existing document body. - Dim body As Body = wordprocessingDocument.MainDocumentPart.Document.Body -``` +[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb#snippet2)] *** When you access to the body of the main document part, add text by -adding instances of the **Paragraph**, **Run**, and **Text** -classes. This generates the required **WordprocessingML** markup. The following lines from +adding instances of the , +, and +classes. This generates the required `WordprocessingML` markup. The following lines from the sample code add the paragraph, run, and text. ### [C#](#tab/cs-2) -```csharp - // Add new text. - Paragraph para = body.AppendChild(new Paragraph()); - Run run = para.AppendChild(new Run()); - run.AppendChild(new Text(txt)); -``` - +[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Add new text. - Dim para As Paragraph = body.AppendChild(New Paragraph()) - Dim run As Run = para.AppendChild(New Run()) - run.AppendChild(New Text(txt)) -``` +[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb#snippet3)] *** ## Sample Code -The example **OpenAndAddToWordprocessingStream** method shown +The example `OpenAndAddToWordprocessingStream` method shown here can be used to open a Word document from an already open stream and append some text using the Open XML SDK. You can call it by passing a handle to an open stream as the first parameter and the text to add as the second. For example, the following code example opens the -Word13.docx file in the Public Documents folder and adds text to it. +file specified in the first argument and adds text from the second argument to it. ### [C#](#tab/cs-3) -```csharp - string strDoc = @"C:\Users\Public\Public Documents\Word13.docx"; - string txt = "Append text in body - OpenAndAddToWordprocessingStream"; - Stream stream = File.Open(strDoc, FileMode.Open); - OpenAndAddToWordprocessingStream(stream, txt); - stream.Close(); -``` - +[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - Dim strDoc As String = "C:\Users\Public\Documents\Word13.docx" - Dim txt As String = "Append text in body - OpenAndAddToWordprocessingStream" - Dim stream As Stream = File.Open(strDoc, FileMode.Open) - OpenAndAddToWordprocessingStream(stream, txt) - stream.Close() -``` +[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb#snippet4)] *** > [!NOTE] -> Notice that the **OpenAddAddToWordprocessingStream** method does not close the stream passed to it. The calling code must do that. +> Notice that the `OpenAddAddToWordprocessingStream` method does not close the stream passed to it. The calling code must do that +> by wrapping the method call in a `using` statement or explicitly calling Dispose. Following is the complete sample code in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs)] +[!code-csharp[](../../samples/word/open_from_a_stream/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb)] +[!code-vb[](../../samples/word/open_from_a_stream/vb/Program.vb#snippet0)] ## See also diff --git a/samples/word/open_from_a_stream/cs/Program.cs b/samples/word/open_from_a_stream/cs/Program.cs index 48645198..60326a64 100644 --- a/samples/word/open_from_a_stream/cs/Program.cs +++ b/samples/word/open_from_a_stream/cs/Program.cs @@ -1,4 +1,4 @@ - +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System.IO; @@ -6,21 +6,38 @@ static void OpenAndAddToWordprocessingStream(Stream stream, string txt) { + // // Open a WordProcessingDocument based on a stream. WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(stream, true); + // - // Assign a reference to the existing document body. + // + // Assign a reference to the document body. MainDocumentPart mainDocumentPart = wordprocessingDocument.MainDocumentPart ?? wordprocessingDocument.AddMainDocumentPart(); mainDocumentPart.Document ??= new Document(); Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body()); + // + // // Add new text. Paragraph para = body.AppendChild(new Paragraph()); Run run = para.AppendChild(new Run()); run.AppendChild(new Text(txt)); + // // Dispose the document handle. wordprocessingDocument.Dispose(); // Caller must close the stream. } +// + +// +string filePath = args[0]; +string txt = args[1]; + +using (FileStream fileStream = new FileStream(filePath, FileMode.Open)) +{ + OpenAndAddToWordprocessingStream(fileStream, txt); +} +// diff --git a/samples/word/open_from_a_stream/vb/Program.vb b/samples/word/open_from_a_stream/vb/Program.vb index d439eb85..4a6cda00 100644 --- a/samples/word/open_from_a_stream/vb/Program.vb +++ b/samples/word/open_from_a_stream/vb/Program.vb @@ -1,3 +1,4 @@ +' Imports System.IO Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing @@ -6,23 +7,49 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module MyModule Sub Main(args As String()) + ' + Dim filePath As String = args(0) + Dim txt As String = args(1) + + Using fileStream As FileStream = New FileStream(filePath, FileMode.Open) + OpenAndAddToWordprocessingStream(fileStream, txt) + End Using + ' End Sub Public Sub OpenAndAddToWordprocessingStream(ByVal stream As Stream, ByVal txt As String) + + ' ' Open a WordProcessingDocument based on a stream. Dim wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(stream, True) + ' + + ' + ' Assign a reference to the document body. + Dim mainDocumentPart As MainDocumentPart = If(wordprocessingDocument.MainDocumentPart, wordprocessingDocument.AddMainDocumentPart()) + + If wordprocessingDocument.MainDocumentPart.Document Is Nothing Then + wordprocessingDocument.MainDocumentPart.Document = New Document() + End If + + If wordprocessingDocument.MainDocumentPart.Document.Body Is Nothing Then + wordprocessingDocument.MainDocumentPart.Document.Body = New Body() + End If - ' Assign a reference to the existing document body. Dim body As Body = wordprocessingDocument.MainDocumentPart.Document.Body + ' + ' ' Add new text. Dim para As Paragraph = body.AppendChild(New Paragraph) Dim run As Run = para.AppendChild(New Run) run.AppendChild(New Text(txt)) + ' ' Dispose the document handle. wordprocessingDocument.Dispose() ' Caller must close the stream. End Sub -End Module \ No newline at end of file +End Module +' From a1b162cc0379e8c9a57ba85ea7eb15a7a1c91736 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Tue, 6 Feb 2024 15:24:33 -0800 Subject: [PATCH 03/53] closes #219 --- ...rocessing-document-for-read-only-access.md | 167 ++++++------------ .../open_for_read_only_access/cs/Program.cs | 95 +++++++++- .../open_for_read_only_access/vb/Program.vb | 66 ++++++- 3 files changed, 205 insertions(+), 123 deletions(-) diff --git a/docs/word/how-to-open-a-word-processing-document-for-read-only-access.md b/docs/word/how-to-open-a-word-processing-document-for-read-only-access.md index 79bdaf9f..b3d0baed 100644 --- a/docs/word/how-to-open-a-word-processing-document-for-read-only-access.md +++ b/docs/word/how-to-open-a-word-processing-document-for-read-only-access.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 02/06/2024 ms.localizationpriority: high --- # Open a word processing document for read-only access @@ -24,6 +24,7 @@ access. --------------------------------------------------------------------------------- ## When to Open a Document for Read-only Access + Sometimes you want to open a document to inspect or retrieve some information, and you want to do so in a way that ensures the document remains unchanged. In these instances, you want to open the document for @@ -32,7 +33,8 @@ programmatically open a read-only word processing document. -------------------------------------------------------------------------------- -## Create a WordprocessingDocument Object +## Create a WordprocessingDocument Object + In the Open XML SDK, the class represents a Word document package. To work with a Word document, first create an instance of the @@ -45,106 +47,74 @@ document. The package can also contain additional parts. Notice that in a Word document, the text in the main document part is represented in the package as XML using WordprocessingML markup. -To create the class instance from the document you call one of the **Open** methods. Several **Open** methods are provided, each with a different +To create the class instance from the document you call one of the `Open` methods. Several `Open` methods are provided, each with a different signature. The methods that let you specify whether a document is editable are listed in the following table. Open Method|Class Library Reference Topic|Description --|--|-- -Open(String, Boolean)|[Open(String, Boolean)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) |Create an instance of the class from the specified file. -Open(Stream, Boolean)|[Open(Stream, Boolean)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) |Create an instance of the class from the specified IO stream. -Open(String, Boolean, OpenSettings)|[Open(String, Boolean, OpenSettings)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) |Create an instance of the class from the specified file. -Open(Stream, Boolean, OpenSettings)|[Open(Stream, Boolean, OpenSettings)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) |Create an instance of the class from the specified I/O stream. +Open(String, Boolean)| |Create an instance of the class from the specified file. +Open(Stream, Boolean)| |Create an instance of the class from the specified IO stream. +Open(String, Boolean, OpenSettings)| |Create an instance of the class from the specified file. +Open(Stream, Boolean, OpenSettings)| |Create an instance of the class from the specified I/O stream. -The table above lists only those **Open** +The table above lists only those `Open` methods that accept a Boolean value as the second parameter to specify whether a document is editable. To open a document for read only access, you specify false for this parameter. -Notice that two of the **Open** methods create +Notice that two of the `Open` methods create an instance of the class based on a string as the first parameter. The first example in the -sample code uses this technique. It uses the first **Open** method in the table above; with a signature +sample code uses this technique. It uses the first `Open` method in the table above; with a signature that requires two parameters. The first parameter takes a string that represents the full path filename from which you want to open the -document. The second parameter is either **true** or **false**; this -example uses **false** and indicates whether +document. The second parameter is either `true` or `false`; this +example uses `false` and indicates whether you want to open the file for editing. -The following code example calls the **Open** +The following code example calls the `Open` Method. ### [C#](#tab/cs-0) -```csharp - // Open a WordprocessingDocument for read-only access based on a filepath. - using (WordprocessingDocument wordDocument = - WordprocessingDocument.Open(filepath, false)) -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - ' Open a WordprocessingDocument for read-only access based on a filepath. - Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, False) -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet1)] *** -The other two **Open** methods create an +The other two `Open` methods create an instance of the class based on an input/output stream. You might employ this approach, -for instance, if you have a Microsoft SharePoint Foundation 2010 +for instance, if you have a Microsoft SharePoint Online application that uses stream input/output, and you want to use the Open XML SDK to work with a document. The following code example opens a document based on a stream. ### [C#](#tab/cs-1) -```csharp - Stream stream = File.Open(strDoc, FileMode.Open); - // Open a WordprocessingDocument for read-only access based on a stream. - using (WordprocessingDocument wordDocument = - WordprocessingDocument.Open(stream, false)) -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-1) -```vb - Dim stream As Stream = File.Open(strDoc, FileMode.Open) - ' Open a WordprocessingDocument for read-only access based on a stream. - Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(stream, False) -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet3)] *** Suppose you have an application that employs the Open XML support in the System.IO.Packaging namespace of the .NET Framework Class Library, and you want to use the Open XML SDK to work with a package read only. -While the Open XML SDK includes method overloads that accept a **Package** as the first parameter, there is not one -that takes a Boolean as the second parameter to indicate whether the -document should be opened for editing. +While the Open XML SDK includes method overloads that accept a +as the first parameter, there is not one that takes a Boolean as +the second parameter to indicate whether the document should be opened for editing. -The recommended method is to open the package read-only to begin with +The recommended method is to open the package as read-only to begin with prior to creating the instance of the class, as shown in the second example in the sample code. The following code example performs this operation. ### [C#](#tab/cs-2) -```csharp - // Open System.IO.Packaging.Package. - Package wordPackage = Package.Open(filepath, FileMode.Open, FileAccess.Read); - - // Open a WordprocessingDocument based on a package. - using (WordprocessingDocument wordDocument = - WordprocessingDocument.Open(wordPackage)) -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-2) -```vb - ' Open System.IO.Packaging.Package. - Dim wordPackage As Package = Package.Open(filepath, FileMode.Open, FileAccess.Read) - - ' Open a WordprocessingDocument based on a package. - Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(wordPackage) -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet2)] *** @@ -154,16 +124,9 @@ a reference to the existing document body, as shown in the following code example. ### [C#](#tab/cs-3) -```csharp - // Assign a reference to the existing document body. - Body body = wordprocessingDocument.MainDocumentPart.Document.Body; -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' Assign a reference to the existing document body. - Dim body As Body = wordprocessingDocument.MainDocumentPart.Document.Body -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet4)] *** @@ -176,71 +139,55 @@ code example. The sample code shows how you can add some text and attempt to save the changes to show that access is read-only. Once you have access to the body of the main document part, you add text by adding instances of the -**Paragraph**, **Run**, and **Text** +, +, and classes. This generates the required WordprocessingML markup. The following code example adds the paragraph, run, and text. ### [C#](#tab/cs-4) -```csharp - // Attempt to add some text. - Paragraph para = body.AppendChild(new Paragraph()); - Run run = para.AppendChild(new Run()); - run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly")); - - // Call Save to generate an exception and show that access is read-only. - wordDocument.MainDocumentPart.Document.Save(); -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - ' Attempt to add some text. - Dim para As Paragraph = body.AppendChild(New Paragraph()) - Dim run As Run = para.AppendChild(New Run()) - run.AppendChild(New Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly")) - - ' Call Save to generate an exception and show that access is read-only. - wordDocument.MainDocumentPart.Document.Save() -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet5)] *** -------------------------------------------------------------------------------- ## Sample Code -The first example method shown here, **OpenWordprocessingDocumentReadOnly**, opens a Word +The first example method shown here, `OpenWordprocessingDocumentReadOnly`, opens a Word document for read-only access. Call it by passing a full path to the file that you want to open. For example, the following code example -opens the Word12.docx file in the Public Documents folder for read-only -access. +opens the file path from the first command line argument for read-only access. ### [C#](#tab/cs-5) -```csharp - OpenWordprocessingDocumentReadonly(@"c:\Users\Public\Public Documents\Word12.docx"); -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - OpenWordprocessingDocumentReadonly("c:\Users\Public\Public Documents\Word12.docx") -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet6)] *** -The second example method, **OpenWordprocessingPackageReadonly**, shows how to -open a Word document for read-only access from a -System.IO.Packaging.Package. Call it by passing a full path to the file -that you want to open. For example, the following code opens the -Word12.docx file in the Public Documents folder for read-only access. +The second example method, `OpenWordprocessingPackageReadonly`, shows how to +open a Word document for read-only access from a . +Call it by passing a full path to the file +that you want to open. For example, the following code example +opens the file path from the first command line argument for read-only access. ### [C#](#tab/cs-6) -```csharp - OpenWordprocessingPackageReadonly(@"c:\Users\Public\Public Documents\Word12.docx"); -``` - +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - OpenWordprocessingPackageReadonly("c:\Users\Public\Public Documents\Word12.docx") -``` +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet7)] *** +The third example method, `OpenWordprocessingStreamReadonly`, shows how to +open a Word document for read-only access from a a stream. +Call it by passing a full path to the file +that you want to open. For example, the following code example +opens the file path from the first command line argument for read-only access. + +### [C#](#tab/cs-6) +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet8)] +### [Visual Basic](#tab/vb-6) +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet8)] +*** > [!IMPORTANT] > If you uncomment the statement that saves the file, the program would throw an **IOException** because the file is opened for read-only access. @@ -248,10 +195,10 @@ Word12.docx file in the Public Documents folder for read-only access. The following is the complete sample code in C\# and VB. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs)] +[!code-csharp[](../../samples/word/open_for_read_only_access/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb)] +[!code-vb[](../../samples/word/open_for_read_only_access/vb/Program.vb#snippet0)] -------------------------------------------------------------------------------- ## See also diff --git a/samples/word/open_for_read_only_access/cs/Program.cs b/samples/word/open_for_read_only_access/cs/Program.cs index 43e0ffe4..c9b3bdb3 100644 --- a/samples/word/open_for_read_only_access/cs/Program.cs +++ b/samples/word/open_for_read_only_access/cs/Program.cs @@ -1,32 +1,111 @@ - +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; +using System.IO.Packaging; +using System.IO; -OpenWordprocessingDocumentReadonly(args[0]); static void OpenWordprocessingDocumentReadonly(string filepath) { + // // Open a WordprocessingDocument based on a filepath. - using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(filepath, false)) + using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(filepath, false)) + // { - if (wordDocument is null) + if (wordProcessingDocument is null) { - throw new ArgumentNullException(nameof(wordDocument)); + throw new ArgumentNullException(nameof(wordProcessingDocument)); } - // Assign a reference to the existing document body. - MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart ?? wordDocument.AddMainDocumentPart(); + + // + // Assign a reference to the existing document body or create a new one if it is null. + MainDocumentPart mainDocumentPart = wordProcessingDocument.MainDocumentPart ?? wordProcessingDocument.AddMainDocumentPart(); mainDocumentPart.Document ??= new Document(); Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body()); + // + // // Attempt to add some text. Paragraph para = body.AppendChild(new Paragraph()); Run run = para.AppendChild(new Run()); run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly")); // Call Save to generate an exception and show that access is read-only. - //mainDocumentPart.Document.Save(); + // mainDocumentPart.Document.Save(); + // + } +} + +static void OpenWordprocessingPackageReadonly(string filepath) +{ + // + // Open System.IO.Packaging.Package. + Package wordPackage = Package.Open(filepath, FileMode.Open, FileAccess.Read); + + // Open a WordprocessingDocument based on a package. + using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(wordPackage)) + // + { + // Assign a reference to the existing document body or create a new one if it is null. + MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart ?? wordDocument.AddMainDocumentPart(); + mainDocumentPart.Document ??= new Document(); + + Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body()); + + // Attempt to add some text. + Paragraph para = body.AppendChild(new Paragraph()); + Run run = para.AppendChild(new Run()); + run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingPackageReadonly")); + + // Call Save to generate an exception and show that access is read-only. + // mainDocumentPart.Document.Save(); + } + + // Close the package. + wordPackage.Close(); +} + + +static void OpenWordprocessingStreamReadonly(string filepath) +{ + // + // Get a stream of the wordprocessing document + using (FileStream fileStream = new FileStream(filepath, FileMode.Open)) + + // Open a WordprocessingDocument for read-only access based on a stream. + using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(fileStream, false)) + // + { + + + // Assign a reference to the existing document body or create a new one if it is null. + MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart ?? wordDocument.AddMainDocumentPart(); + mainDocumentPart.Document ??= new Document(); + + Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body()); + + // Attempt to add some text. + Paragraph para = body.AppendChild(new Paragraph()); + Run run = para.AppendChild(new Run()); + run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingStreamReadonly")); + + // Call Save to generate an exception and show that access is read-only. + // mainDocumentPart.Document.Save(); } } +// + +// +OpenWordprocessingDocumentReadonly(args[0]); +// + +// +OpenWordprocessingPackageReadonly(args[0]); +// + +// +OpenWordprocessingStreamReadonly(args[0]); +// diff --git a/samples/word/open_for_read_only_access/vb/Program.vb b/samples/word/open_for_read_only_access/vb/Program.vb index 386fceec..66f8027b 100644 --- a/samples/word/open_for_read_only_access/vb/Program.vb +++ b/samples/word/open_for_read_only_access/vb/Program.vb @@ -1,3 +1,4 @@ +' Imports System.IO Imports System.IO.Packaging Imports DocumentFormat.OpenXml.Packaging @@ -7,30 +8,62 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module MyModule Sub Main(args As String()) + ' + OpenWordprocessingDocumentReadonly(args(0)) + ' + + ' + OpenWordprocessingPackageReadonly(args(0)) + ' + + ' + OpenWordprocessingStreamReadonly(args(0)) + ' End Sub Public Sub OpenWordprocessingDocumentReadonly(ByVal filepath As String) + + ' ' Open a WordprocessingDocument based on a filepath. - Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, False) - ' Assign a reference to the existing document body. - Dim body As Body = wordDocument.MainDocumentPart.Document.Body + Using wordProcessingDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, False) + ' + + ' + ' Assign a reference to the document body. + Dim mainDocumentPart As MainDocumentPart = If(wordProcessingDocument.MainDocumentPart, wordProcessingDocument.AddMainDocumentPart()) + + If wordProcessingDocument.MainDocumentPart.Document Is Nothing Then + wordProcessingDocument.MainDocumentPart.Document = New Document() + End If + + If wordProcessingDocument.MainDocumentPart.Document.Body Is Nothing Then + wordProcessingDocument.MainDocumentPart.Document.Body = New Body() + End If + + Dim body As Body = wordProcessingDocument.MainDocumentPart.Document.Body + ' + ' ' Attempt to add some text. Dim para As Paragraph = body.AppendChild(New Paragraph()) Dim run As Run = para.AppendChild(New Run()) run.AppendChild(New Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly")) ' Call Save to generate an exception and show that access is read-only. - ' wordDocument.MainDocumentPart.Document.Save() + 'wordProcessingDocument.MainDocumentPart.Document.Save() + ' End Using End Sub Public Sub OpenWordprocessingPackageReadonly(ByVal filepath As String) + ' ' Open System.IO.Packaging.Package. Dim wordPackage As Package = Package.Open(filepath, FileMode.Open, FileAccess.Read) ' Open a WordprocessingDocument based on a package. Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(wordPackage) + ' + ' Assign a reference to the existing document body. Dim body As Body = wordDocument.MainDocumentPart.Document.Body @@ -46,4 +79,27 @@ Module MyModule ' Close the package. wordPackage.Close() End Sub -End Module \ No newline at end of file + + Public Sub OpenWordprocessingStreamReadonly(ByVal filepath As String) + ' + ' Get a stream of the wordprocessing document + Using fileStream As FileStream = New FileStream(filepath, FileMode.Open) + ' Open a WordprocessingDocument for read-only access based on a stream. + Using wordDocument As WordprocessingDocument = WordprocessingDocument.Open(fileStream, False) + ' + + ' Assign a reference to the existing document body. + Dim body As Body = wordDocument.MainDocumentPart.Document.Body + + ' Attempt to add some text. + Dim para As Paragraph = body.AppendChild(New Paragraph()) + Dim run As Run = para.AppendChild(New Run()) + run.AppendChild(New Text("Append text in body, but text is not saved - OpenWordprocessingStreamReadonly")) + + ' Call Save to generate an exception and show that access is read-only. + ' wordDocument.MainDocumentPart.Document.Save() + End Using + End Using + End Sub +End Module +' From 3368d85529169786932680d08e92e44747d7160c Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Wed, 7 Feb 2024 15:45:14 -0800 Subject: [PATCH 04/53] closes #218 --- ...a-table-into-a-word-processing-document.md | 243 +++++------------- samples/word/insert_a_table/cs/Program.cs | 24 +- samples/word/insert_a_table/vb/Program.vb | 54 +++- 3 files changed, 132 insertions(+), 189 deletions(-) diff --git a/docs/word/how-to-insert-a-table-into-a-word-processing-document.md b/docs/word/how-to-insert-a-table-into-a-word-processing-document.md index e145ca17..1adda8a1 100644 --- a/docs/word/how-to-insert-a-table-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-table-into-a-word-processing-document.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 02/07/2024 ms.localizationpriority: high --- # Insert a table into a word processing document @@ -25,56 +25,45 @@ document. ## Getting a WordprocessingDocument Object To open an existing document, instantiate the class as shown in the -following **using** statement. In the same +following `using` statement. In the same statement, open the word processing file at the specified filepath by -using the **Open** method, with the Boolean -parameter set to **true** in order to enable +using the method, with the Boolean +parameter set to `true` in order to enable editing the document. ### [C#](#tab/cs-0) -```csharp - using (WordprocessingDocument doc = - WordprocessingDocument.Open(filepath, true)) - { - // Insert other code here. - } -``` - +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Using doc As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) - ' Insert other code here. - End Using -``` +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet1)] *** -The **using** statement provides a recommended +The `using` statement provides a recommended alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method +that the method (internal method used by the Open XML SDK to clean up resources) is automatically called when the closing brace is reached. The block that follows the using statement establishes a scope for the object that is created or named in the using statement, in this case doc. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -**Dispose** is automatically called when you -exit the block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +automatically saves and closes the object as part of its implementation, and because + is automatically called when you +exit the block, you do not have to explicitly call and + as long as you use `using`. ## Structure of a Table -The basic document structure of a **WordProcessingML** document consists of the **document** and **body** -elements, followed by one or more block level elements such as **p**, which represents a paragraph. A paragraph -contains one or more **r** elements. The r -stands for run, which is a region of text with a common set of -properties, such as formatting. A run contains one or more **t** elements. The **t** +The basic document structure of a `WordProcessingML` document consists of the `document` and `body` +elements, followed by one or more block level elements such as `p`, which represents a paragraph. A paragraph +contains one or more `r` elements. The r stands for run, which is a region of text with a common set of +properties, such as formatting. A run contains one or more `t` elements. The `t` element contains a range of text.The document might contain a table as in this example. A table is a set of paragraphs (and other block-level -content) arranged in rows and columns. Tables in **WordprocessingML** are defined via the **tbl** element, which is analogous to the HTML table +content) arranged in rows and columns. Tables in `WordprocessingML` +are defined via the `tbl` element, which is analogous to the HTML table tag. Consider an empty one-cell table (i.e. a table with one row, one column) and 1 point borders on all sides. This table is represented by -the following **WordprocessingML** markup +the following `WordprocessingML` markup segment. ```xml @@ -83,7 +72,7 @@ segment. - + @@ -103,159 +92,67 @@ segment. ``` This table specifies table-wide properties of 100% of page width using -the **tblW** element, a set of table borders -using the **tblBorders** element, the table +the `tblW` element, a set of table borders +using the `tblBorders` element, the table grid, which defines a set of shared vertical edges within the table -using the **tblGrid** element, and a single -table row using the **tr** element. +using the `tblGrid` element, and a single +table row using the `tr` element. ## How the Sample Code Works -In sample code, after you open the document in the **using** statement, you create a new [Table](/dotnet/api/documentformat.openxml.wordprocessing.table) object. Then you create a [TableProperties](/dotnet/api/documentformat.openxml.wordprocessing.tableproperties) object and specify its -border information. The **TableProperties** -class contains an overloaded constructor [TableProperties()](/dotnet/api/documentformat.openxml.wordprocessing.tableproperties.-ctor) that takes a **params** array of type [OpenXmlElement](/dotnet/api/documentformat.openxml.openxmlelement). The code uses this -constructor to instantiate a **TableProperties** object with [BorderType](/dotnet/api/documentformat.openxml.wordprocessing.bordertype) objects for each border, -instantiating each **BorderType** and -specifying its value using object initializers. After it has been -instantiated, append the **TableProperties** -object to the table. +In sample code, after you open the document in the `using` statement, you create a new + object. Then you create +a object and specify its border information. +The class contains an overloaded +constructor +that takes a `params` array of type . The code uses this +constructor to instantiate a `TableProperties` object with +objects for each border, instantiating each `BorderType` and specifying its value using object initializers. +After it has been instantiated, append the `TableProperties` object to the table. ### [C#](#tab/cs-1) -```csharp - // Create an empty table. - Table table = new Table(); - - // Create a TableProperties object and specify its border information. - TableProperties tblProp = new TableProperties( - new TableBorders( - new TopBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 }, - new BottomBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 }, - new LeftBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 }, - new RightBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 }, - new InsideHorizontalBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 }, - new InsideVerticalBorder() { Val = new EnumValue(BorderValues.Dashed), Size = 24 } - ) - ); - // Append the TableProperties object to the empty table. - table.AppendChild(tblProp); -``` - +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - ' Create an empty table. - Dim table As New Table() - - ' Create a TableProperties object and specify its border information. - Dim tblProp As New TableProperties( - New TableBorders( - New TopBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New BottomBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New LeftBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New RightBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New InsideHorizontalBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New InsideVerticalBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24})) - - ' Append the TableProperties object to the empty table. - table.AppendChild(Of TableProperties)(tblProp) -``` +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet2)] *** The code creates a table row. This section of the code makes extensive -use of the overloaded [Append\[\])](/dotnet/api/documentformat.openxml.openxmlelement.append) methods, which classes derived -from **OpenXmlElement** inherit. The **Append** methods provide a way to either append a -single element or to append a portion of an XML tree, to the end of the -list of child elements under a given parent element. Next, the code -creates a [TableCell](/dotnet/api/documentformat.openxml.wordprocessing.tablecell) object, which represents an -individual table cell, and specifies the width property of the table -cell using a [TableCellProperties](/dotnet/api/documentformat.openxml.wordprocessing.tablecellproperties) object, and the cell -content ("Hello, World!") using a [Text](/dotnet/api/documentformat.openxml.wordprocessing.text) object. In the Open XML Wordprocessing -schema, a paragraph element (**\**) -contains run elements (**\**) which, in -turn, contain text elements (**\**). To -insert text within a table cell using the API, you must create a [Paragraph](/dotnet/api/documentformat.openxml.wordprocessing.paragraph) object that contains a **Run** object that contains a **Text** object that contains the text you want to -insert in the cell. You then append the **Paragraph** object to the **TableCell** object. This creates the proper XML -structure for inserting text into a cell. The **TableCell** is then appended to the [TableRow](/dotnet/api/documentformat.openxml.wordprocessing.tablerow) object. +use of the overloaded methods, +which classes derived from `OpenXmlElement` inherit. The `Append` methods provide +a way to either append a single element or to append a portion of an XML tree, +to the end of the list of child elements under a given parent element. Next, the code +creates a object, which represents +an individual table cell, and specifies the width property of the table cell using a + object, and the cell +content ("Hello, World!") using a object. +In the Open XML Wordprocessing schema, a paragraph element (``) contains run elements (``) +which, in turn, contain text elements (``). To insert text within a table cell using the API, you must create a + object that contains a +object that contains a `Text` object that contains the text you want to insert in the cell. +You then append the `Paragraph` object to the `TableCell` object. This creates the proper XML +structure for inserting text into a cell. The `TableCell` is then appended to the + object. ### [C#](#tab/cs-2) -```csharp - // Create a row. - TableRow tr = new TableRow(); - - // Create a cell. - TableCell tc1 = new TableCell(); - - // Specify the width property of the table cell. - tc1.Append(new TableCellProperties(new TableCellWidth() { Type = TableWidthUnitValues.Dxa, Width = "2400" })); - - // Specify the table cell content. - tc1.Append(new Paragraph(new Run(new Text("Hello, World!")))); - - // Append the table cell to the table row. - tr.Append(tc1); -``` - +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Create a row. - Dim tr As New TableRow() - - ' Create a cell. - Dim tc1 As New TableCell() - - ' Specify the width property of the table cell. - tc1.Append(New TableCellProperties(New TableCellWidth() With {.Type = TableWidthUnitValues.Dxa, .Width = "2400"})) - - ' Specify the table cell content. - tc1.Append(New Paragraph(New Run(New Text("Hello, World!")))) - - ' Append the table cell to the table row. - tr.Append(tc1) -``` +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet3)] *** -The code then creates a second table cell. The final section of code -creates another table cell using the overloaded **TableCell** constructor [TableCell(String)](/dotnet/api/documentformat.openxml.wordprocessing.tablecell.-ctor) that takes the [OuterXml](/dotnet/api/documentformat.openxml.openxmlelement.outerxml) property of an existing **TableCell** object as its only argument. After -creating the second table cell, the code appends the **TableCell** to the **TableRow**, appends the **TableRow** to the **Table**, and the **Table** -to the [Document](/dotnet/api/documentformat.openxml.wordprocessing.document) object. +The code then creates a second table cell. The final section of code creates another table cell +using the overloaded `TableCell` constructor +that takes the property of an existing +`TableCell` object as its only argument. After creating the second table cell, the code appends +the `TableCell` to the `TableRow`, appends the `TableRow` to the `Table`, and the `Table` +to the object. ### [C#](#tab/cs-3) -```csharp - // Create a second table cell by copying the OuterXml value of the first table cell. - TableCell tc2 = new TableCell(tc1.OuterXml); - - // Append the table cell to the table row. - tr.Append(tc2); - - // Append the table row to the table. - table.Append(tr); - - // Append the table to the document. - doc.MainDocumentPart.Document.Body.Append(table); - - // Save changes to the MainDocumentPart. - doc.MainDocumentPart.Document.Save(); -``` - +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' Create a second table cell by copying the OuterXml value of the first table cell. - Dim tc2 As New TableCell(tc1.OuterXml) - - ' Append the table cell to the table row. - tr.Append(tc2) - - ' Append the table row to the table. - table.Append(tr) - - ' Append the table to the document. - doc.MainDocumentPart.Document.Body.Append(table) - - ' Save changes to the MainDocumentPart. - doc.MainDocumentPart.Document.Save() -``` +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet4)] *** @@ -264,33 +161,25 @@ to the [Document](/dotnet/api/documentformat.openxml.wordprocessing.document) ob The following code example shows how to create a table, set its properties, insert text into a cell in the table, copy a cell, and then insert the table into a word processing document. You can invoke the -method **CreateTable** by using the following +method `CreateTable` by using the following call. ### [C#](#tab/cs-4) -```csharp - string fileName = @"C:\Users\Public\Documents\Word10.docx"; - CreateTable(fileName); -``` - +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - Dim fileName As String = "C:\Users\Public\Documents\Word10.docx" - CreateTable(fileName) -``` +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet5)] *** -After you run the program inspect the file "Word10.docx" to see the -inserted table. +After you run the program inspect the file to see the inserted table. Following is the complete sample code in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs)] +[!code-csharp[](../../samples/word/insert_a_table/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb)] +[!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet)] ## See also diff --git a/samples/word/insert_a_table/cs/Program.cs b/samples/word/insert_a_table/cs/Program.cs index 376d3141..448c53bd 100644 --- a/samples/word/insert_a_table/cs/Program.cs +++ b/samples/word/insert_a_table/cs/Program.cs @@ -1,19 +1,21 @@ +// using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; -CreateTable(args[0]); // Insert a table into a word processing document. static void CreateTable(string fileName) { // Use the file name and path passed in as an argument - // to open an existing Word 2007 document. + // to open an existing Word document. - using (WordprocessingDocument doc - = WordprocessingDocument.Open(fileName, true)) + // + using (WordprocessingDocument doc = WordprocessingDocument.Open(fileName, true)) + // { + // // Create an empty table. Table table = new Table(); @@ -61,7 +63,9 @@ static void CreateTable(string fileName) // Append the TableProperties object to the empty table. table.AppendChild(tblProp); + // + // // Create a row. TableRow tr = new TableRow(); @@ -77,7 +81,9 @@ static void CreateTable(string fileName) // Append the table cell to the table row. tr.Append(tc1); + // + // // Create a second table cell by copying the OuterXml value of the first table cell. TableCell tc2 = new TableCell(tc1.OuterXml); @@ -94,5 +100,13 @@ static void CreateTable(string fileName) // Append the table to the document. doc.MainDocumentPart.Document.Body.Append(table); + // } -} \ No newline at end of file +} +// + +// +string filePath = args[0]; + +CreateTable(filePath); +// diff --git a/samples/word/insert_a_table/vb/Program.vb b/samples/word/insert_a_table/vb/Program.vb index 51a1195d..52042654 100644 --- a/samples/word/insert_a_table/vb/Program.vb +++ b/samples/word/insert_a_table/vb/Program.vb @@ -1,3 +1,4 @@ +' Imports DocumentFormat.OpenXml Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing @@ -12,6 +13,10 @@ Imports TopBorder = DocumentFormat.OpenXml.Wordprocessing.TopBorder Module MyModule Sub Main(args As String()) + ' + Dim filePath As String = args(0) + CreateTable(filePath) + ' End Sub @@ -20,21 +25,52 @@ Module MyModule ' Use the file name and path passed in as an argument ' to open an existing Word 2007 document. + ' Using doc As WordprocessingDocument = WordprocessingDocument.Open(fileName, True) + ' + + ' ' Create an empty table. Dim table As New Table() ' Create a TableProperties object and specify its border information. Dim tblProp As New TableProperties(New TableBorders( - New TopBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New BottomBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New LeftBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New RightBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New InsideHorizontalBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24}, - New InsideVerticalBorder() With {.Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), .Size = 24})) + New TopBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }, + New BottomBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }, + New LeftBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }, + New RightBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }, + New InsideHorizontalBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }, + New InsideVerticalBorder() With + { + .Val = New EnumValue(Of BorderValues)(BorderValues.Dashed), + .Size = 24 + }) + ) ' Append the TableProperties object to the empty table. table.AppendChild(Of TableProperties)(tblProp) + ' + ' ' Create a row. Dim tr As New TableRow() @@ -49,7 +85,9 @@ Module MyModule ' Append the table cell to the table row. tr.Append(tc1) + ' + ' ' Create a second table cell by copying the OuterXml value of the first table cell. Dim tc2 As New TableCell(tc1.OuterXml) @@ -61,6 +99,8 @@ Module MyModule ' Append the table to the document. doc.MainDocumentPart.Document.Body.Append(table) + ' End Using End Sub -End Module \ No newline at end of file +End Module +' From 5f30e911042d0549304f2b37f3e49389c050be98 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Thu, 8 Feb 2024 11:48:03 -0800 Subject: [PATCH 05/53] closes #310 --- ...to-add-a-new-document-part-to-a-package.md | 3 +- ...ackage-part-to-a-document-part-in-a-dif.md | 11 +---- docs/general/how-to-create-a-package.md | 10 +---- ...tents-of-a-document-part-from-a-package.md | 12 +----- ...o-remove-a-document-part-from-a-package.md | 11 +---- ...heme-part-in-a-word-processing-document.md | 14 +------ ...rch-and-replace-text-in-a-document-part.md | 13 +----- docs/includes/using-statement.md | 11 +++++ .../how-to-apply-a-theme-to-a-presentation.md | 7 +--- ...fill-color-of-a-shape-in-a-presentation.md | 7 +--- ...w-to-delete-a-slide-from-a-presentation.md | 2 +- ...or-from-all-the-slides-in-a-presentatio.md | 7 +--- ...e-external-hyperlinks-in-a-presentation.md | 7 +--- ...l-the-text-in-a-slide-in-a-presentation.md | 7 +--- ...he-text-in-all-slides-in-a-presentation.md | 7 +--- ...les-of-all-the-slides-in-a-presentation.md | 9 +--- ...-insert-a-new-slide-into-a-presentation.md | 9 +--- ...agraph-from-one-presentation-to-another.md | 8 +--- ...ide-to-a-new-position-in-a-presentation.md | 8 +--- ...n-a-table-in-a-word-processing-document.md | 12 +----- ...ssing-document-by-providing-a-file-name.md | 12 +----- ...comment-into-a-word-processing-document.md | 9 +--- ...picture-into-a-word-processing-document.md | 42 ++++--------------- ...a-table-into-a-word-processing-document.md | 13 +----- ...omments-from-a-word-processing-document.md | 6 +-- 25 files changed, 43 insertions(+), 214 deletions(-) create mode 100644 docs/includes/using-statement.md diff --git a/docs/general/how-to-add-a-new-document-part-to-a-package.md b/docs/general/how-to-add-a-new-document-part-to-a-package.md index bc5ba2d2..90d9714d 100644 --- a/docs/general/how-to-add-a-new-document-part-to-a-package.md +++ b/docs/general/how-to-add-a-new-document-part-to-a-package.md @@ -40,8 +40,7 @@ The code starts with opening a package file by passing a file name to one of the *** -The **using** statement provides a recommended alternative to the typical .Create, .Save, .Close sequence. It ensures that the **Dispose** method (internal method used by the Open XML SDK to clean up resources) is automatically called when the closing brace is reached. The block that follows the **using** statement establishes a scope for the object that is created or named in the **using** statement, in this case **wordDoc**. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because the **Dispose** method is automatically called when you exit the block; you do not have to explicitly call **Save** and **Close**, as long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/word/structure.md)] diff --git a/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md b/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md index 5d9bf19f..dbfbf88a 100644 --- a/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md +++ b/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md @@ -57,16 +57,7 @@ order to enable editing the document. ``` *** -The `using` statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the using -statement establishes a scope for the object that is created or named in -the `using` statement. Because the class in the Open XML SDK -automatically saves and closes the object as part of its implementation, and because - is automatically called when you -exit the block, you do not have to explicitly call . +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/general/how-to-create-a-package.md b/docs/general/how-to-create-a-package.md index c40dea47..a7946d10 100644 --- a/docs/general/how-to-create-a-package.md +++ b/docs/general/how-to-create-a-package.md @@ -59,15 +59,7 @@ template. ``` *** -The **using** statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** () method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing bracket is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **wordDoc**. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -**Dispose** is automatically called when you exit the bracketed block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] Once you have created the Word document package, you can add parts to it. To add the main document part you call . Having done that, diff --git a/docs/general/how-to-get-the-contents-of-a-document-part-from-a-package.md b/docs/general/how-to-get-the-contents-of-a-document-part-from-a-package.md index 8f2a83bc..1dc5c19a 100644 --- a/docs/general/how-to-get-the-contents-of-a-document-part-from-a-package.md +++ b/docs/general/how-to-get-the-contents-of-a-document-part-from-a-package.md @@ -54,17 +54,7 @@ opened in read-only mode to avoid accidental changes. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **wordDoc**. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -the **Dispose** method is automatically called -when you exit the block; you do not have to explicitly call **Save** and **Close**─as -long as you use using. +[!include[Using Statement](../includes/using-statement.md)] --------------------------------------------------------------------------------- diff --git a/docs/general/how-to-remove-a-document-part-from-a-package.md b/docs/general/how-to-remove-a-document-part-from-a-package.md index fcfacedf..128cd48a 100644 --- a/docs/general/how-to-remove-a-document-part-from-a-package.md +++ b/docs/general/how-to-remove-a-document-part-from-a-package.md @@ -54,16 +54,7 @@ should be opened in read/write mode. *** -The **using** statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **wordDoc**. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -the **Dispose** method is automatically called -when you exit the block; you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] --------------------------------------------------------------------------------- diff --git a/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md b/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md index a8648b65..5b499b48 100644 --- a/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md +++ b/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md @@ -49,19 +49,7 @@ to **true** to enable editing the document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *wordDoc*. Because -the class in the -Open XML SDK automatically saves and closes the object as part of its -**System.IDisposable** implementation, and -because **Dispose** is automatically called -when you exit the block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] ## How to Change Theme in a Word Package diff --git a/docs/general/how-to-search-and-replace-text-in-a-document-part.md b/docs/general/how-to-search-and-replace-text-in-a-document-part.md index 9a73ba0a..9e57abad 100644 --- a/docs/general/how-to-search-and-replace-text-in-a-document-part.md +++ b/docs/general/how-to-search-and-replace-text-in-a-document-part.md @@ -53,18 +53,7 @@ to **true** to enable editing the document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *wordDoc*. Because -the class in the -Open XML SDK automatically saves and closes the object as part of its -**System.IDisposable** implementation, and -because **Dispose** is automatically called -when you exit the block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/includes/using-statement.md b/docs/includes/using-statement.md new file mode 100644 index 00000000..77938662 --- /dev/null +++ b/docs/includes/using-statement.md @@ -0,0 +1,11 @@ +The `using` statement provides a recommended +alternative to the typical .Create, .Save, .Close sequence. It ensures +that the method (internal method +used by the Open XML SDK to clean up resources) is automatically called +when the closing brace is reached. The block that follows the using +statement establishes a scope for the object that is created or named in +the using statement. Because the class in the Open XML SDK +automatically saves and closes the object as part of its implementation, and because + is automatically called when you +exit the block, you do not have to explicitly call and + as long as you use `using`. \ No newline at end of file diff --git a/docs/presentation/how-to-apply-a-theme-to-a-presentation.md b/docs/presentation/how-to-apply-a-theme-to-a-presentation.md index 2182b0ad..4c37d68e 100644 --- a/docs/presentation/how-to-apply-a-theme-to-a-presentation.md +++ b/docs/presentation/how-to-apply-a-theme-to-a-presentation.md @@ -51,12 +51,7 @@ represents the path for the target presentation document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **themeDocument** and **presentationDocument**. +[!include[Using Statement](../includes/using-statement.md)] ----------------------------------------------------------------------------- diff --git a/docs/presentation/how-to-change-the-fill-color-of-a-shape-in-a-presentation.md b/docs/presentation/how-to-change-the-fill-color-of-a-shape-in-a-presentation.md index 8d0cb092..6939c994 100644 --- a/docs/presentation/how-to-change-the-fill-color-of-a-shape-in-a-presentation.md +++ b/docs/presentation/how-to-change-the-fill-color-of-a-shape-in-a-presentation.md @@ -53,12 +53,7 @@ you want to open the document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *ppt*. +[!include[Using Statement](../includes/using-statement.md)] ## The Structure of the Shape Tree diff --git a/docs/presentation/how-to-delete-a-slide-from-a-presentation.md b/docs/presentation/how-to-delete-a-slide-from-a-presentation.md index f27d74ca..5e679caa 100644 --- a/docs/presentation/how-to-delete-a-slide-from-a-presentation.md +++ b/docs/presentation/how-to-delete-a-slide-from-a-presentation.md @@ -76,7 +76,7 @@ statement. *** -The **using** statement provides a recommended alternative to the typical .Open, .Save, .Close sequence. It ensures that the **Dispose** method (internal method used by the Open XML SDK to clean up resources) is automatically called when the closing brace is reached. The block that follows the **using** statement establishes a scope for the object that is created or named in the **using** statement, in this case **presentationDocument**. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/presentation/structure.md)] diff --git a/docs/presentation/how-to-delete-all-the-comments-by-an-author-from-all-the-slides-in-a-presentatio.md b/docs/presentation/how-to-delete-all-the-comments-by-an-author-from-all-the-slides-in-a-presentatio.md index 83f73734..2600ecd0 100644 --- a/docs/presentation/how-to-delete-all-the-comments-by-an-author-from-all-the-slides-in-a-presentatio.md +++ b/docs/presentation/how-to-delete-all-the-comments-by-an-author-from-all-the-slides-in-a-presentatio.md @@ -59,12 +59,7 @@ Options. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *doc*. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/presentation/structure.md)] diff --git a/docs/presentation/how-to-get-all-the-external-hyperlinks-in-a-presentation.md b/docs/presentation/how-to-get-all-the-external-hyperlinks-in-a-presentation.md index d7ba13a1..d69df315 100644 --- a/docs/presentation/how-to-get-all-the-external-hyperlinks-in-a-presentation.md +++ b/docs/presentation/how-to-get-all-the-external-hyperlinks-in-a-presentation.md @@ -58,12 +58,7 @@ path for the file from which you want to open the document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **document**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/presentation/how-to-get-all-the-text-in-a-slide-in-a-presentation.md b/docs/presentation/how-to-get-all-the-text-in-a-slide-in-a-presentation.md index 083855d4..56c0af4f 100644 --- a/docs/presentation/how-to-get-all-the-text-in-a-slide-in-a-presentation.md +++ b/docs/presentation/how-to-get-all-the-text-in-a-slide-in-a-presentation.md @@ -56,12 +56,7 @@ document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **presentationDocument**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/presentation/how-to-get-all-the-text-in-all-slides-in-a-presentation.md b/docs/presentation/how-to-get-all-the-text-in-all-slides-in-a-presentation.md index 1c03a39c..96ffdbf2 100644 --- a/docs/presentation/how-to-get-all-the-text-in-all-slides-in-a-presentation.md +++ b/docs/presentation/how-to-get-all-the-text-in-all-slides-in-a-presentation.md @@ -56,12 +56,7 @@ document. *** -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **presentationDocument**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/presentation/how-to-get-the-titles-of-all-the-slides-in-a-presentation.md b/docs/presentation/how-to-get-the-titles-of-all-the-slides-in-a-presentation.md index f06c1b30..44d82d82 100644 --- a/docs/presentation/how-to-get-the-titles-of-all-the-slides-in-a-presentation.md +++ b/docs/presentation/how-to-get-the-titles-of-all-the-slides-in-a-presentation.md @@ -55,14 +55,7 @@ document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case -*presentationDocument*. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/presentation/structure.md)] diff --git a/docs/presentation/how-to-insert-a-new-slide-into-a-presentation.md b/docs/presentation/how-to-insert-a-new-slide-into-a-presentation.md index 1c0c65f2..0ed94c26 100644 --- a/docs/presentation/how-to-insert-a-new-slide-into-a-presentation.md +++ b/docs/presentation/how-to-insert-a-new-slide-into-a-presentation.md @@ -51,14 +51,7 @@ document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case -*presentationDocument*. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/presentation/structure.md)] diff --git a/docs/presentation/how-to-move-a-paragraph-from-one-presentation-to-another.md b/docs/presentation/how-to-move-a-paragraph-from-one-presentation-to-another.md index e800cebe..6e5103dd 100644 --- a/docs/presentation/how-to-move-a-paragraph-from-one-presentation-to-another.md +++ b/docs/presentation/how-to-move-a-paragraph-from-one-presentation-to-another.md @@ -52,13 +52,7 @@ for the file from which you want to open the document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *doc*. +[!include[Using Statement](../includes/using-statement.md)] [!include[Structure](../includes/presentation/structure.md)] diff --git a/docs/presentation/how-to-move-a-slide-to-a-new-position-in-a-presentation.md b/docs/presentation/how-to-move-a-slide-to-a-new-position-in-a-presentation.md index e8bf6e84..b63644a6 100644 --- a/docs/presentation/how-to-move-a-slide-to-a-new-position-in-a-presentation.md +++ b/docs/presentation/how-to-move-a-slide-to-a-new-position-in-a-presentation.md @@ -57,13 +57,7 @@ open the document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **presentationDocument**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md b/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md index d6232a15..bc951426 100644 --- a/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md +++ b/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md @@ -42,17 +42,7 @@ To open an existing document, instantiate the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -**Dispose** is automatically called when you -exit the block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] ## The Structure of a Table diff --git a/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md b/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md index 05e0f3ea..b4af6ddd 100644 --- a/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md +++ b/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md @@ -68,17 +68,7 @@ bracketed block, as shown in the following code example. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** () method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing bracket is reached. The block that follows the **using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case **wordDocument**. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -**Dispose** is automatically called when you -exit the bracketed block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] Once you have created the Word document package, you can add parts to it. To add the main document part you call the method of the class. Having done that, diff --git a/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md b/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md index 02f2c21f..b010c28b 100644 --- a/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md @@ -48,14 +48,7 @@ editing in the document. ``` *** - -The **using** statement provides a recommended -alternative to the typical .Open, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -that is used by the Open XML SDK to clean up resources) is automatically -called when the closing brace is reached. The block that follows the -**using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case *document*. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- diff --git a/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md b/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md index 4a17b366..1b291772 100644 --- a/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md @@ -12,55 +12,31 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 02/08/2024 ms.localizationpriority: high --- # Insert a picture into a word processing document This topic shows how to use the classes in the Open XML SDK for Office to programmatically add a picture to a word processing document. - - -------------------------------------------------------------------------------- ## Opening an Existing Document for Editing -To open an existing document, instantiate the class as shown in -the following **using** statement. In the same -statement, open the word processing file at the specified **filepath** by using the [Open(String, Boolean)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method, with the -Boolean parameter set to **true** in order to +To open an existing document, instantiate the +class as shown in the following `using` statement. In the same +statement, open the word processing file at the specified `filepath`by using the + +method, with the Boolean parameter set to `true` in order to enable editing the document. ### [C#](#tab/cs-0) -```csharp - using (WordprocessingDocument wordprocessingDocument = - WordprocessingDocument.Open(filepath, true)) - { - // Insert other code here. - } -``` - +[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Using wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) - ' Insert other code here. - End Using -``` +[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb#snippet1)] *** - -The **using** statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the **Dispose** method (internal method -that is used by the Open XML SDK to clean up resources) is automatically -called when the closing brace is reached. The block that follows the -**using** statement establishes a scope for the -object that is created or named in the **using** statement, in this case -*wordprocessingDocument*. Because the class in the Open XML SDK -automatically saves and closes the object as part of its **System.IDisposable** implementation, and because -**Dispose** is automatically called when you -exit the block, you do not have to explicitly call **Save** and **Close**─as -long as you use **using**. +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- ## The XML Representation of the Graphic Object diff --git a/docs/word/how-to-insert-a-table-into-a-word-processing-document.md b/docs/word/how-to-insert-a-table-into-a-word-processing-document.md index 1adda8a1..ff98004f 100644 --- a/docs/word/how-to-insert-a-table-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-table-into-a-word-processing-document.md @@ -37,18 +37,7 @@ editing the document. [!code-vb[](../../samples/word/insert_a_table/vb/Program.vb#snippet1)] *** - -The `using` statement provides a recommended -alternative to the typical .Create, .Save, .Close sequence. It ensures -that the method (internal method -used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the using -statement establishes a scope for the object that is created or named in -the using statement, in this case doc. Because the class in the Open XML SDK -automatically saves and closes the object as part of its implementation, and because - is automatically called when you -exit the block, you do not have to explicitly call and - as long as you use `using`. +[!include[Using Statement](../includes/using-statement.md)] ## Structure of a Table diff --git a/docs/word/how-to-retrieve-comments-from-a-word-processing-document.md b/docs/word/how-to-retrieve-comments-from-a-word-processing-document.md index c285d5ba..2adc581d 100644 --- a/docs/word/how-to-retrieve-comments-from-a-word-processing-document.md +++ b/docs/word/how-to-retrieve-comments-from-a-word-processing-document.md @@ -35,11 +35,7 @@ the Boolean parameter to `false`. [!code-vb[](../../samples/word/retrieve_comments/vb/Program.vb#snippet1)] *** -The `using` statement provides a recommended alternative to the .Open, .Save, .Close sequence. It ensures -that the `Dispose` method (internal method used by the Open XML SDK to clean up resources) is automatically called -when the closing brace is reached. The block that follows the `using` statement establishes a scope for the -object that is created or named in the `using` statement, in this case `wordDoc`. - +[!include[Using Statement](../includes/using-statement.md)] -------------------------------------------------------------------------------- ## Comments Element From 37c5abd1ec0fe09c39ed25117565a9548d820b03 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Thu, 8 Feb 2024 12:13:07 -0800 Subject: [PATCH 06/53] closes #217 --- ...picture-into-a-word-processing-document.md | 170 ++---------------- samples/samples.sln | 7 + samples/word/insert_a_picture/cs/Program.cs | 18 +- samples/word/insert_a_picture/vb/Program.vb | 103 ++++++----- 4 files changed, 98 insertions(+), 200 deletions(-) diff --git a/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md b/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md index 1b291772..51e51649 100644 --- a/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-picture-into-a-word-processing-document.md @@ -25,8 +25,8 @@ This topic shows how to use the classes in the Open XML SDK for Office to progra To open an existing document, instantiate the class as shown in the following `using` statement. In the same -statement, open the word processing file at the specified `filepath`by using the - +statement, open the word processing file at the specified `filepath` +by using the method, with the Boolean parameter set to `true` in order to enable editing the document. @@ -68,151 +68,24 @@ The following XML Schema fragment defines the contents of this element ## How the Sample Code Works -After you have opened the document, add the [ImagePart](/dotnet/api/documentformat.openxml.packaging.imagepart) object to the [MainDocumentPart](/dotnet/api/documentformat.openxml.packaging.maindocumentpart) object by using a file +After you have opened the document, add the +object to the object by using a file stream as shown in the following code segment. ### [C#](#tab/cs-1) -```csharp - MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart; - ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg); - using (FileStream stream = new FileStream(fileName, FileMode.Open)) - { - imagePart.FeedData(stream); - } - AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart)); -``` - +[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim mainPart As MainDocumentPart = wordprocessingDocument.MainDocumentPart - Dim imagePart As ImagePart = mainPart.AddImagePart(ImagePartType.Jpeg) - Using stream As New FileStream(fileName, FileMode.Open) - imagePart.FeedData(stream) - End Using - AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart)) -``` +[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb#snippet2)] *** To add the image to the body, first define the reference of the image. -Then, append the reference to the body. The element should be in a [Run](/dotnet/api/documentformat.openxml.wordprocessing.run). +Then, append the reference to the body. The element should be in a . ### [C#](#tab/cs-2) -```csharp - // Define the reference of the image. - var element = - new Drawing( - new DW.Inline( - new DW.Extent() { Cx = 990000L, Cy = 792000L }, - new DW.EffectExtent() - { - LeftEdge = 0L, - TopEdge = 0L, - RightEdge = 0L, - BottomEdge = 0L - }, - new DW.DocProperties() - { - Id = (UInt32Value)1U, - Name = "Picture 1" - }, - new DW.NonVisualGraphicFrameDrawingProperties( - new A.GraphicFrameLocks() { NoChangeAspect = true }), - new A.Graphic( - new A.GraphicData( - new PIC.Picture( - new PIC.NonVisualPictureProperties( - new PIC.NonVisualDrawingProperties() - { - Id = (UInt32Value)0U, - Name = "New Bitmap Image.jpg" - }, - new PIC.NonVisualPictureDrawingProperties()), - new PIC.BlipFill( - new A.Blip( - new A.BlipExtensionList( - new A.BlipExtension() - { - Uri = - "{28A0092B-C50C-407E-A947-70E740481C1C}" - }) - ) - { - Embed = relationshipId, - CompressionState = - A.BlipCompressionValues.Print - }, - new A.Stretch( - new A.FillRectangle())), - new PIC.ShapeProperties( - new A.Transform2D( - new A.Offset() { X = 0L, Y = 0L }, - new A.Extents() { Cx = 990000L, Cy = 792000L }), - new A.PresetGeometry( - new A.AdjustValueList() - ) { Preset = A.ShapeTypeValues.Rectangle })) - ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) - ) - { - DistanceFromTop = (UInt32Value)0U, - DistanceFromBottom = (UInt32Value)0U, - DistanceFromLeft = (UInt32Value)0U, - DistanceFromRight = (UInt32Value)0U, - EditId = "50D07946" - }); - - // Append the reference to the body. The element should be in - // a DocumentFormat.OpenXml.Wordprocessing.Run. - wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element))); -``` - +[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Define the image reference. - Dim element = New Drawing( _ - New DW.Inline( _ - New DW.Extent() With {.Cx = 990000L, .Cy = 792000L}, _ - New DW.EffectExtent() With {.LeftEdge = 0L, .TopEdge = 0L, .RightEdge = 0L, .BottomEdge = 0L}, _ - New DW.DocProperties() With {.Id = CType(1UI, UInt32Value), .Name = "Picture1"}, _ - New DW.NonVisualGraphicFrameDrawingProperties( _ - New A.GraphicFrameLocks() With {.NoChangeAspect = True} _ - ), _ - New A.Graphic(New A.GraphicData( _ - New PIC.Picture( _ - New PIC.NonVisualPictureProperties( _ - New PIC.NonVisualDrawingProperties() With {.Id = 0UI, .Name = "Koala.jpg"}, _ - New PIC.NonVisualPictureDrawingProperties() _ - ), _ - New PIC.BlipFill( _ - New A.Blip( _ - New A.BlipExtensionList( _ - New A.BlipExtension() With {.Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"}) _ - ) With {.Embed = relationshipId, .CompressionState = A.BlipCompressionValues.Print}, _ - New A.Stretch( _ - New A.FillRectangle() _ - ) _ - ), _ - New PIC.ShapeProperties( _ - New A.Transform2D( _ - New A.Offset() With {.X = 0L, .Y = 0L}, _ - New A.Extents() With {.Cx = 990000L, .Cy = 792000L}), _ - New A.PresetGeometry( _ - New A.AdjustValueList() _ - ) With {.Preset = A.ShapeTypeValues.Rectangle} _ - ) _ - ) _ - ) With {.Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"} _ - ) _ - ) With {.DistanceFromTop = 0UI, _ - .DistanceFromBottom = 0UI, _ - .DistanceFromLeft = 0UI, _ - .DistanceFromRight = 0UI} _ - ) - - ' Append the reference to the body, the element should be in - ' a DocumentFormat.OpenXml.Wordprocessing.Run. - wordDoc.MainDocumentPart.Document.Body.AppendChild(New Paragraph(New Run(element))) -``` +[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb#snippet3)] *** @@ -220,37 +93,26 @@ Then, append the reference to the body. The element should be in a [Run](/dotnet ## Sample Code The following code example adds a picture to an existing word document. -In your code, you can call the **InsertAPicture** method by passing in the path of +In your code, you can call the `InsertAPicture` method by passing in the path of the word document, and the path of the file that contains the picture. -For example, the following call inserts the picture "MyPic.jpg" into the -file "Word9.docx," located at the specified paths. +For example, the following call inserts the picture. ### [C#](#tab/cs-3) -```csharp - string document = @"C:\Users\Public\Documents\Word9.docx"; - string fileName = @"C:\Users\Public\Documents\MyPic.jpg"; - InsertAPicture(document, fileName); -``` - +[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - Dim document As String = "C:\Users\Public\Documents\Word9.docx" - Dim fileName As String = "C:\Users\Public\Documents\MyPic.jpg" - InsertAPicture(document, fileName) -``` +[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb#snippet4)] *** -After you run the code, look at the file "Word9.docx" to see the -inserted picture. +After you run the code, look at the file to see the inserted picture. The following is the complete sample code in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs)] +[!code-csharp[](../../samples/word/insert_a_picture/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb)] +[!code-vb[](../../samples/word/insert_a_picture/vb/Program.vb#snippet)] -------------------------------------------------------------------------------- diff --git a/samples/samples.sln b/samples/samples.sln index 590ac98c..0d04415f 100644 --- a/samples/samples.sln +++ b/samples/samples.sln @@ -334,6 +334,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "working_with_tables_cs", "w EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "working_with_tables_vb", "word\working_with_tables\vb\working_with_tables_vb.vbproj", "{4EB1FCC9-E1E2-4D2A-ACF9-A3A31AA947A5}" EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "insert_a_picture_vb", "word\insert_a_picture\vb\insert_a_picture_vb.vbproj", "{6170C4E1-A109-435A-BF59-026C85B3BD9C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -980,6 +982,10 @@ Global {4EB1FCC9-E1E2-4D2A-ACF9-A3A31AA947A5}.Debug|Any CPU.Build.0 = Debug|Any CPU {4EB1FCC9-E1E2-4D2A-ACF9-A3A31AA947A5}.Release|Any CPU.ActiveCfg = Release|Any CPU {4EB1FCC9-E1E2-4D2A-ACF9-A3A31AA947A5}.Release|Any CPU.Build.0 = Release|Any CPU + {6170C4E1-A109-435A-BF59-026C85B3BD9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6170C4E1-A109-435A-BF59-026C85B3BD9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6170C4E1-A109-435A-BF59-026C85B3BD9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6170C4E1-A109-435A-BF59-026C85B3BD9C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1144,6 +1150,7 @@ Global {72BE6D64-0AEB-4090-A6F9-B255D291BF14} = {7ACDC26B-C774-4004-8553-87E862D1E71F} {A43A75AB-D6B6-4D31-99F7-6951AFEF502D} = {D207D3D7-FD4D-4FD4-A7D0-79A82086FB6F} {4EB1FCC9-E1E2-4D2A-ACF9-A3A31AA947A5} = {D207D3D7-FD4D-4FD4-A7D0-79A82086FB6F} + {6170C4E1-A109-435A-BF59-026C85B3BD9C} = {D207D3D7-FD4D-4FD4-A7D0-79A82086FB6F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {721B3030-08D7-4412-9087-D1CFBB3F5046} diff --git a/samples/word/insert_a_picture/cs/Program.cs b/samples/word/insert_a_picture/cs/Program.cs index 4d786ce0..786fe252 100644 --- a/samples/word/insert_a_picture/cs/Program.cs +++ b/samples/word/insert_a_picture/cs/Program.cs @@ -1,3 +1,4 @@ +// using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; @@ -7,17 +8,19 @@ using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing; using PIC = DocumentFormat.OpenXml.Drawing.Pictures; -InsertAPicture(args[0], args[1]); static void InsertAPicture(string document, string fileName) { + // using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true)) + // { if (wordprocessingDocument.MainDocumentPart is null) { throw new ArgumentNullException("MainDocumentPart is null."); } + // MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart; ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg); @@ -28,11 +31,13 @@ static void InsertAPicture(string document, string fileName) } AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart)); + // } } static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId) { + // // Define the reference of the image. var element = new Drawing( @@ -104,4 +109,13 @@ static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId // Append the reference to body, the element should be in a Run. wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element))); -} \ No newline at end of file + // +} +// + +// +string documentPath = args[0]; +string picturePath = args[1]; + +InsertAPicture(documentPath, picturePath); +// diff --git a/samples/word/insert_a_picture/vb/Program.vb b/samples/word/insert_a_picture/vb/Program.vb index 5359cddc..462603d7 100644 --- a/samples/word/insert_a_picture/vb/Program.vb +++ b/samples/word/insert_a_picture/vb/Program.vb @@ -1,3 +1,4 @@ +' Imports System.IO Imports DocumentFormat.OpenXml Imports DocumentFormat.OpenXml.Packaging @@ -6,14 +7,24 @@ Imports A = DocumentFormat.OpenXml.Drawing Imports DW = DocumentFormat.OpenXml.Drawing.Wordprocessing Imports PIC = DocumentFormat.OpenXml.Drawing.Pictures -Module Program ` - Sub Main(args As String())` - End Sub` +Module Program + Sub Main(args As String()) + ' + Dim documentPath As String = args(0) + Dim picturePath As String = args(1) + + InsertAPicture(documentPath, picturePath) + ' + End Sub + + - - Public Sub InsertAPicture(ByVal document As String, ByVal fileName As String) + ' Using wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(document, True) + ' + + ' Dim mainPart As MainDocumentPart = wordprocessingDocument.MainDocumentPart Dim imagePart As ImagePart = mainPart.AddImagePart(ImagePartType.Jpeg) @@ -23,52 +34,56 @@ Module Program ` End Using AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart)) + ' End Using End Sub Private Sub AddImageToBody(ByVal wordDoc As WordprocessingDocument, ByVal relationshipId As String) + ' ' Define the reference of the image. - Dim element = New Drawing( _ - New DW.Inline( _ - New DW.Extent() With {.Cx = 990000L, .Cy = 792000L}, _ - New DW.EffectExtent() With {.LeftEdge = 0L, .TopEdge = 0L, .RightEdge = 0L, .BottomEdge = 0L}, _ - New DW.DocProperties() With {.Id = CType(1UI, UInt32Value), .Name = "Picture1"}, _ - New DW.NonVisualGraphicFrameDrawingProperties( _ - New A.GraphicFrameLocks() With {.NoChangeAspect = True} _ - ), _ - New A.Graphic(New A.GraphicData( _ - New PIC.Picture( _ - New PIC.NonVisualPictureProperties( _ - New PIC.NonVisualDrawingProperties() With {.Id = 0UI, .Name = "Koala.jpg"}, _ - New PIC.NonVisualPictureDrawingProperties() _ - ), _ - New PIC.BlipFill( _ - New A.Blip( _ - New A.BlipExtensionList( _ - New A.BlipExtension() With {.Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"}) _ - ) With {.Embed = relationshipId, .CompressionState = A.BlipCompressionValues.Print}, _ - New A.Stretch( _ - New A.FillRectangle() _ - ) _ - ), _ - New PIC.ShapeProperties( _ - New A.Transform2D( _ - New A.Offset() With {.X = 0L, .Y = 0L}, _ - New A.Extents() With {.Cx = 990000L, .Cy = 792000L}), _ - New A.PresetGeometry( _ - New A.AdjustValueList() _ - ) With {.Preset = A.ShapeTypeValues.Rectangle} _ - ) _ - ) _ - ) With {.Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"} _ - ) _ - ) With {.DistanceFromTop = 0UI, _ - .DistanceFromBottom = 0UI, _ - .DistanceFromLeft = 0UI, _ - .DistanceFromRight = 0UI} _ + Dim element = New Drawing( + New DW.Inline( + New DW.Extent() With {.Cx = 990000L, .Cy = 792000L}, + New DW.EffectExtent() With {.LeftEdge = 0L, .TopEdge = 0L, .RightEdge = 0L, .BottomEdge = 0L}, + New DW.DocProperties() With {.Id = CType(1UI, UInt32Value), .Name = "Picture1"}, + New DW.NonVisualGraphicFrameDrawingProperties( + New A.GraphicFrameLocks() With {.NoChangeAspect = True} + ), + New A.Graphic(New A.GraphicData( + New PIC.Picture( + New PIC.NonVisualPictureProperties( + New PIC.NonVisualDrawingProperties() With {.Id = 0UI, .Name = "Koala.jpg"}, + New PIC.NonVisualPictureDrawingProperties() + ), + New PIC.BlipFill( + New A.Blip( + New A.BlipExtensionList( + New A.BlipExtension() With {.Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"}) + ) With {.Embed = relationshipId, .CompressionState = A.BlipCompressionValues.Print}, + New A.Stretch( + New A.FillRectangle() + ) + ), + New PIC.ShapeProperties( + New A.Transform2D( + New A.Offset() With {.X = 0L, .Y = 0L}, + New A.Extents() With {.Cx = 990000L, .Cy = 792000L}), + New A.PresetGeometry( + New A.AdjustValueList() + ) With {.Preset = A.ShapeTypeValues.Rectangle} + ) + ) + ) With {.Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"} + ) + ) With {.DistanceFromTop = 0UI, + .DistanceFromBottom = 0UI, + .DistanceFromLeft = 0UI, + .DistanceFromRight = 0UI} ) ' Append the reference to body, the element should be in a Run. wordDoc.MainDocumentPart.Document.Body.AppendChild(New Paragraph(New Run(element))) + ' End Sub -End Module \ No newline at end of file +End Module +' From 428e4e479f5b1f67ec31703cfe7f479eaf0e2c03 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Thu, 8 Feb 2024 13:52:26 -0800 Subject: [PATCH 07/53] closes #216 --- ...comment-into-a-word-processing-document.md | 203 +++++------------- samples/word/insert_a_comment/cs/Program.cs | 24 ++- samples/word/insert_a_comment/vb/Program.vb | 23 +- 3 files changed, 99 insertions(+), 151 deletions(-) diff --git a/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md b/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md index b010c28b..dc355027 100644 --- a/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md +++ b/docs/word/how-to-insert-a-comment-into-a-word-processing-document.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 02/08/2024 ms.localizationpriority: medium --- # Insert a comment into a word processing document @@ -25,27 +25,16 @@ word processing document. -------------------------------------------------------------------------------- ## Open the Existing Document for Editing To open an existing document, instantiate the class as shown in -the following **using** statement. In the same +the following `using` statement. In the same statement, open the word processing file at the specified *filepath* by -using the [Open(String, Boolean)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method, with the -Boolean parameter set to **true** to enable +using the +method, with the Boolean parameter set to `true` to enable editing in the document. ### [C#](#tab/cs-0) -```csharp - using (WordprocessingDocument document = - WordprocessingDocument.Open(filepath, true)) - { - // Insert other code here. - } -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Using document As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) - ' Insert other code here. - End Using -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet1)] *** [!include[Using Statement](../includes/using-statement.md)] @@ -53,88 +42,47 @@ editing in the document. -------------------------------------------------------------------------------- ## How the Sample Code Works + After you open the document, you can find the first paragraph to attach -a comment. The code finds the first paragraph by calling the -[First](/dotnet/api/system.linq.enumerable.first) +a comment. The code finds the first paragraph by calling the extension method on all the descendant elements of the document element -that are of type [Paragraph](/dotnet/api/documentformat.openxml.wordprocessing.paragraph). The **First** method is a member -of the -[System.Linq.Enumerable](/dotnet/api/system.linq.enumerable) -class. The **System.Linq.Enumerable** class -provides extension methods for objects that implement the -[System.Collections.Generic.IEnumerable](/dotnet/api/system.collections.generic.ienumerable-1) -interface. +that are of type . The `First` method is a member +of the class. The `System.Linq.Enumerable` class +provides extension methods for objects that implement the interface. ### [C#](#tab/cs-1) -```csharp - Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants().First(); - Comments comments = null; - string id = "0"; -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim firstParagraph As Paragraph = document.MainDocumentPart.Document.Descendants(Of Paragraph)().First() - Dim comments As Comments = Nothing - Dim id As String = "0" -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet2)] *** -The code first determines whether a [WordprocessingCommentsPart](/dotnet/api/documentformat.openxml.packaging.wordprocessingcommentspart) part exists. To -do this, call the [MainDocumentPart](/dotnet/api/documentformat.openxml.packaging.maindocumentpart) generic method, **GetPartsCountOfType**, and specify a kind of **WordprocessingCommentsPart**. +The code first determines whether a +part exists. To do this, call the generic method, +`GetPartsCountOfType`, and specify a kind of `WordprocessingCommentsPart`. -If a **WordprocessingCommentsPart** part -exists, the code obtains a new **Id** value for -the [Comment](/dotnet/api/documentformat.openxml.wordprocessing.comment) object that it will add to the -existing **WordprocessingCommentsPart** [Comments](/dotnet/api/documentformat.openxml.wordprocessing.comments) collection object. It does this by -finding the highest **Id** attribute value -given to a **Comment** in the **Comments** collection object, incrementing the -value by one, and then storing that as the **Id** value.If no **WordprocessingCommentsPart** part exists, the code -creates one using the [AddNewPart\()](/dotnet/api/documentformat.openxml.packaging.openxmlpartcontainer.addnewpart) method of the [MainDocumentPart](/dotnet/api/documentformat.openxml.packaging.maindocumentpart) object and then adds a -**Comments** collection object to it. +If a `WordprocessingCommentsPart` part exists, the code obtains a new `Id` value for +the object that it will add to the +existing `WordprocessingCommentsPart` +collection object. It does this by finding the highest `Id` attribute value +given to a `Comment` in the `Comments` collection object, incrementing the +value by one, and then storing that as the `Id` value.If no `WordprocessingCommentsPart` part exists, the code +creates one using the +method of the object and then adds a +`Comments` collection object to it. ### [C#](#tab/cs-2) -```csharp - if (document.MainDocumentPart.GetPartsCountOfType() > 0) - { - comments = - document.MainDocumentPart.WordprocessingCommentsPart.Comments; - if (comments.HasChildren) - { - id = (comments.Descendants().Select(e => int.Parse(e.Id.Value)).Max() + 1).ToString(); - } - } - else - { - WordprocessingCommentsPart commentPart = - document.MainDocumentPart.AddNewPart(); - commentPart.Comments = new Comments(); - comments = commentPart.Comments; - } -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - If document.MainDocumentPart.GetPartsCountOfType(Of WordprocessingCommentsPart)() > 0 Then - comments = document.MainDocumentPart.WordprocessingCommentsPart.Comments - If comments.HasChildren Then - id = comments.Descendants(Of Comment)().Select(Function(e) e.Id.Value).Max() - End If - Else - Dim commentPart As WordprocessingCommentsPart = document.MainDocumentPart.AddNewPart(Of WordprocessingCommentsPart)() - commentPart.Comments = New Comments() - comments = commentPart.Comments - End If -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet3)] *** -The **Comment** and **Comments** objects represent comment and comments -elements, respectively, in the Open XML Wordprocessing schema. A **Comment** must be added to a **Comments** object so the code first instantiates a -**Comments** object (using the string arguments -**author**, **initials**, -and **comments** that were passed in to the **AddCommentOnFirstParagraph** method). +The `Comment` and `Comments` objects represent comment and comments +elements, respectively, in the Open XML Wordprocessing schema. A `Comment` +must be added to a `Comments` object so the code first instantiates a +`Comments` object (using the string arguments `author`, `initials`, +and `comments` that were passed in to the `AddCommentOnFirstParagraph` method). The comment is represented by the following WordprocessingML code example. . @@ -145,31 +93,15 @@ example. . ``` -The code then appends the **Comment** to the -**Comments** object and saves the changes. This +The code then appends the `Comment` to the `Comments` object and saves the changes. This creates the required XML document object model (DOM) tree structure in -memory which consists of a **comments** parent -element with **comment** child elements under +memory which consists of a `comments` parent element with `comment` child elements under it. ### [C#](#tab/cs-3) -```csharp - Paragraph p = new Paragraph(new Run(new Text(comment))); - Comment cmt = new Comment() { Id = id, - Author = author, Initials = initials, Date = DateTime.Now }; - cmt.AppendChild(p); - comments.AppendChild(cmt); - comments.Save(); -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - Dim p As New Paragraph(New Run(New Text(comment))) - Dim cmt As New Comment() With {.Id = id, .Author = author, .Initials = initials, .Date = Date.Now} - cmt.AppendChild(p) - comments.AppendChild(cmt) - comments.Save() -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet4)] *** @@ -184,18 +116,17 @@ comments part in a WordprocessingML document. ``` -With the **Comment** object instantiated, the -code associates the **Comment** with a range in -the Wordprocessing document. [CommentRangeStart](/dotnet/api/documentformat.openxml.wordprocessing.commentrangestart) and [CommentRangeEnd](/dotnet/api/documentformat.openxml.wordprocessing.commentrangeend) objects correspond to the -**commentRangeStart** and **commentRangeEnd** elements in the Open XML -Wordprocessing schema. A **CommentRangeStart** -object is given as the argument to the [InsertBefore\(T, OpenXmlElement)](/dotnet/api/documentformat.openxml.openxmlcompositeelement.insertbefore) method -of the [Paragraph](/dotnet/api/documentformat.openxml.wordprocessing.paragraph) object and a **CommentRangeEnd** object is passed to the [InsertAfter\(T, OpenXmlElement)](/dotnet/api/documentformat.openxml.openxmlcompositeelement.insertafter) method. -This creates a comment range that extends from immediately before the -first character of the first paragraph in the Wordprocessing document to -immediately after the last character of the first paragraph. - -A [CommentReference](/dotnet/api/documentformat.openxml.wordprocessing.commentreference) object represents a +With the **Comment** object instantiated, the code associates the **Comment** with a range in +the Wordprocessing document. and + objects correspond to the +**commentRangeStart** and **commentRangeEnd** elements in the Open XML Wordprocessing schema. +A **CommentRangeStart** object is given as the argument to the +method of the object and a **CommentRangeEnd** +object is passed to the method. +This creates a comment range that extends from immediately before the first character of the first paragraph +in the Wordprocessing document to immediately after the last character of the first paragraph. + +A object represents a **commentReference** element in the Open XML Wordprocessing schema. A commentReference links a specific comment in the **WordprocessingCommentsPart** part (the Comments.xml file in the Wordprocessing package) to a specific location in the @@ -207,27 +138,12 @@ a given comment, so the commentReference **id** attribute must match the comment **id** attribute value that it links to. In the sample, the code adds a **commentReference** element by using the API, and instantiates a **CommentReference** object, -specifying the **Id** value, and then adds it to a [Run](/dotnet/api/documentformat.openxml.wordprocessing.run) object. +specifying the **Id** value, and then adds it to a object. ### [C#](#tab/cs-4) -```csharp - firstParagraph.InsertBefore(new CommentRangeStart() - { Id = id }, firstParagraph.GetFirstChild()); - - var cmtEnd = firstParagraph.InsertAfter(new CommentRangeEnd() - { Id = id }, firstParagraph.Elements().Last()); - - firstParagraph.InsertAfter(new Run(new CommentReference() { Id = id }), cmtEnd); -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - firstParagraph.InsertBefore(New CommentRangeStart() With {.Id = id}, firstParagraph.GetFirstChild(Of Run)()) - - Dim cmtEnd = firstParagraph.InsertAfter(New CommentRangeEnd() With {.Id = id}, firstParagraph.Elements(Of Run)().Last()) - - firstParagraph.InsertAfter(New Run(New CommentReference() With {.Id = id}), cmtEnd) -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet5)] *** @@ -235,31 +151,22 @@ specifying the **Id** value, and then adds it to a [Run](/dotnet/api/documentfor ## Sample Code The following code example shows how to create a comment and associate it with a range in a word processing document. To call the method **AddCommentOnFirstParagraph** pass in the path of -the document, your name, your initials, and the comment text. For -example, the following call to the **AddCommentOnFirstParagraph** method writes the -comment "This is my comment." in the file "Word8.docx." +the document, your name, your initials, and the comment text. ### [C#](#tab/cs-5) -```csharp - AddCommentOnFirstParagraph(@"C:\Users\Public\Documents\Word8.docx", - author, initials, "This is my comment."); -``` - +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - AddCommentOnFirstParagraph("C:\Users\Public\Documents\Word8.docx", _ - author, initials, comment) -``` +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet6)] *** Following is the complete sample code in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs)] +[!code-csharp[](../../samples/word/insert_a_comment/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb)] +[!code-vb[](../../samples/word/insert_a_comment/vb/Program.vb#snippet)] -------------------------------------------------------------------------------- ## See also diff --git a/samples/word/insert_a_comment/cs/Program.cs b/samples/word/insert_a_comment/cs/Program.cs index e1b9e924..f7e0c890 100644 --- a/samples/word/insert_a_comment/cs/Program.cs +++ b/samples/word/insert_a_comment/cs/Program.cs @@ -1,16 +1,18 @@ +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Linq; -AddCommentOnFirstParagraph(args[0], args[1], args[2], args[3]); // Insert a comment on the first paragraph. static void AddCommentOnFirstParagraph(string fileName, string author, string initials, string comment) { // Use the file name and path passed in as an // argument to open an existing Wordprocessing document. + // using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true)) + // { if (document.MainDocumentPart is null/* || document.MainDocumentPart.WordprocessingCommentsPart is null*/) { @@ -20,12 +22,15 @@ static void AddCommentOnFirstParagraph(string fileName, string author, string in WordprocessingCommentsPart wordprocessingCommentsPart = document.MainDocumentPart.WordprocessingCommentsPart ?? document.MainDocumentPart.AddNewPart(); // Locate the first paragraph in the document. + // Paragraph firstParagraph = document.MainDocumentPart.Document.Descendants().First(); wordprocessingCommentsPart.Comments ??= new Comments(); string id = "0"; + // // Verify that the document contains a // WordProcessingCommentsPart part; if not, add a new one. + // if (document.MainDocumentPart.GetPartsOfType().Count() > 0) { if (wordprocessingCommentsPart.Comments.HasChildren) @@ -45,8 +50,10 @@ static void AddCommentOnFirstParagraph(string fileName, string author, string in .Max() + 1).ToString(); } } + // // Compose a new Comment and add it to the Comments part. + // Paragraph p = new Paragraph(new Run(new Text(comment))); Comment cmt = new Comment() @@ -59,9 +66,11 @@ static void AddCommentOnFirstParagraph(string fileName, string author, string in cmt.AppendChild(p); wordprocessingCommentsPart.Comments.AppendChild(cmt); wordprocessingCommentsPart.Comments.Save(); + // // Specify the text range for the Comment. // Insert the new CommentRangeStart before the first run of paragraph. + // firstParagraph.InsertBefore(new CommentRangeStart() { Id = id }, firstParagraph.GetFirstChild()); @@ -71,5 +80,16 @@ static void AddCommentOnFirstParagraph(string fileName, string author, string in // Compose a run with CommentReference and insert it. firstParagraph.InsertAfter(new Run(new CommentReference() { Id = id }), cmtEnd); + // } -} \ No newline at end of file +} +// + +// +string fileName = args[0]; +string author = args[1]; +string initials = args[2]; +string comment = args[3]; + +AddCommentOnFirstParagraph(fileName, author, initials, comment); +// diff --git a/samples/word/insert_a_comment/vb/Program.vb b/samples/word/insert_a_comment/vb/Program.vb index c556b09c..323ea624 100644 --- a/samples/word/insert_a_comment/vb/Program.vb +++ b/samples/word/insert_a_comment/vb/Program.vb @@ -1,8 +1,17 @@ +' Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing Module Program Sub Main(args As String()) + ' + Dim fileName As String = args(0) + Dim author As String = args(1) + Dim initials As String = args(2) + Dim comment As String = args(3) + + AddCommentOnFirstParagraph(fileName, author, initials, comment) + ' End Sub @@ -11,14 +20,20 @@ Module Program Public Sub AddCommentOnFirstParagraph(ByVal fileName As String, ByVal author As String, ByVal initials As String, ByVal comment As String) ' Use the file name and path passed in as an ' argument to open an existing Wordprocessing document. + ' Using document As WordprocessingDocument = WordprocessingDocument.Open(fileName, True) + ' + ' Locate the first paragraph in the document. + ' Dim firstParagraph As Paragraph = document.MainDocumentPart.Document.Descendants(Of Paragraph)().First() Dim comments As Comments = Nothing Dim id As String = "0" + ' ' Verify that the document contains a ' WordProcessingCommentsPart part; if not, add a new one. + ' If document.MainDocumentPart.GetPartsOfType(Of WordprocessingCommentsPart).Count() > 0 Then comments = document.MainDocumentPart.WordprocessingCommentsPart.Comments If comments.HasChildren Then @@ -31,16 +46,20 @@ Module Program commentPart.Comments = New Comments() comments = commentPart.Comments End If + ' ' Compose a new Comment and add it to the Comments part. + ' Dim p As New Paragraph(New Run(New Text(comment))) Dim cmt As New Comment() With {.Id = id, .Author = author, .Initials = initials, .Date = DateTime.Now} cmt.AppendChild(p) comments.AppendChild(cmt) comments.Save() + ' ' Specify the text range for the Comment. ' Insert the new CommentRangeStart before the first run of paragraph. + ' firstParagraph.InsertBefore(New CommentRangeStart() With {.Id = id}, firstParagraph.GetFirstChild(Of Run)()) ' Insert the new CommentRangeEnd after last run of paragraph. @@ -48,6 +67,8 @@ Module Program ' Compose a run with CommentReference and insert it. firstParagraph.InsertAfter(New Run(New CommentReference() With {.Id = id}), cmtEnd) + ' End Using End Sub -End Module \ No newline at end of file +End Module +' From b2fc6f1400e39febc1a0e2338b1d0fdc0dda15d9 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Fri, 9 Feb 2024 12:11:59 -0800 Subject: [PATCH 08/53] closes #215 --- ...-styles-from-a-word-processing-document.md | 186 ++++-------------- samples/word/extract_styles/cs/Program.cs | 61 ++++-- samples/word/extract_styles/vb/Program.vb | 44 ++++- 3 files changed, 119 insertions(+), 172 deletions(-) diff --git a/docs/word/how-to-extract-styles-from-a-word-processing-document.md b/docs/word/how-to-extract-styles-from-a-word-processing-document.md index c75f4d25..15afc193 100644 --- a/docs/word/how-to-extract-styles-from-a-word-processing-document.md +++ b/docs/word/how-to-extract-styles-from-a-word-processing-document.md @@ -12,16 +12,15 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 02/09/2024 ms.localizationpriority: medium --- # Extract styles from a word processing document This topic shows how to use the classes in the Open XML SDK for Office to programmatically extract the styles or stylesWithEffects part -from a word processing document to an -[XDocument](/dotnet/api/system.xml.linq.xdocument) -instance. It contains an example **ExtractStylesPart** method to +from a word processing document to an +instance. It contains an example `ExtractStylesPart` method to illustrate this task. @@ -30,7 +29,7 @@ illustrate this task. ## ExtractStylesPart Method -You can use the **ExtractStylesPart** sample method to retrieve an **XDocument** instance that contains the styles or +You can use the `ExtractStylesPart` sample method to retrieve an `XDocument` instance that contains the styles or stylesWithEffects part for a Microsoft Word document. Be aware that in a document created in Word 2010, there will only be a single styles part; Word 2013+ adds a second stylesWithEffects part. To provide for "round-tripping" a document from Word 2013+ to Word @@ -42,29 +41,20 @@ Word 2013+ adds to the document.) You (and your application) must interpret the results of retrieving the styles or stylesWithEffects part. -The **ExtractStylesPart** procedure accepts a two parameters: the first +The `ExtractStylesPart` procedure accepts a two parameters: the first parameter contains a string indicating the path of the file from which you want to extract styles, and the second indicates whether you want to retrieve the styles part, or the newer stylesWithEffects part (basically, you must call this procedure two times for Word 2013+ -documents, retrieving each the part). The procedure returns an **XDocument** instance that contains the complete +documents, retrieving each the part). The procedure returns an `XDocument` instance that contains the complete styles or stylesWithEffects part that you requested, with all the style information for the document (or a null reference, if the part you requested does not exist). ### [C#](#tab/cs-0) -```csharp - public static XDocument ExtractStylesPart( - string fileName, - bool getStylesWithEffectsPart = true) -``` - +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Function ExtractStylesPart( - ByVal fileName As String, - Optional ByVal getStylesWithEffectsPart As Boolean = True) As XDocument -``` +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet1)] *** @@ -77,38 +67,16 @@ The complete code listing for the method can be found in the [Sample Code](#samp To call the sample method, pass a string for the first parameter that contains the file name of the document from which to extract the styles, and a Boolean for the second parameter that specifies whether the type -of part to retrieve is the styleWithEffects part (**true**), or the styles part (**false**). The following sample code shows an example. -When you have the **XDocument** instance you +of part to retrieve is the styleWithEffects part (`true`), or the styles part (`false`). The following sample code shows an example. +When you have the `XDocument` instance you can do what you want with it; in the following sample code the content -of the **XDocument** instance is displayed to +of the `XDocument` instance is displayed to the console. ### [C#](#tab/cs-1) -```csharp - string filename = @"C:\Users\Public\Documents\StylesFrom.docx"; - - // Retrieve the StylesWithEffects part. You could pass false in the - // second parameter to retrieve the Styles part instead. - var styles = ExtractStylesPart(filename, true); - - // If the part was retrieved, send the contents to the console. - if (styles != null) - Console.WriteLine(styles.ToString()); -``` - +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim filename As String = "C:\Users\Public\Documents\StylesFrom.docx" - - ' Retrieve the stylesWithEffects part. You could pass False - ' in the second parameter to retrieve the styles part instead. - Dim styles = ExtractStylesPart(filename, True) - - ' If the part was retrieved, send the contents to the console. - If styles IsNot Nothing Then - Console.WriteLine(styles.ToString()) - End If -``` +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet2)] *** @@ -116,92 +84,32 @@ the console. ## How the Code Works -The code starts by creating a variable named **styles** that the method returns before it exits. - -### [C#](#tab/cs-2) -```csharp - // Declare a variable to hold the XDocument. - XDocument styles = null; - // Code removed here... - // Return the XDocument instance. - return styles; -``` - -### [Visual Basic](#tab/vb-2) -```vb - ' Declare a variable to hold the XDocument. - Dim styles As XDocument = Nothing - ' Code removed here... - ' Return the XDocument instance. - Return styles -``` -*** - - -The code continues by opening the document by using the [Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method and indicating that the -document should be open for read-only access (the final false -parameter). Given the open document, the code uses the [MainDocumentPart](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.maindocumentpart) property to navigate to -the main document part, and then prepares a variable named **stylesPart** to hold a reference to the styles part. +The code starts by creating a variable named `styles` to contain the return value for the method. +The code continues by opening the document by using the +method and indicating that the document should be open for read-only access (the final false +parameter). Given the open document, the code uses the +property to navigate to the main document part, and then prepares a variable named `stylesPart` to hold a reference to the styles part. ### [C#](#tab/cs-3) -```csharp - // Open the document for read access and get a reference. - using (var document = - WordprocessingDocument.Open(fileName, false)) - { - // Get a reference to the main document part. - var docPart = document.MainDocumentPart; - - // Assign a reference to the appropriate part to the - // stylesPart variable. - StylesPart stylesPart = null; - // Code removed here... - } -``` - +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-3) -```vb - ' Open the document for read access and get a reference. - Using document = WordprocessingDocument.Open(fileName, False) - - ' Get a reference to the main document part. - Dim docPart = document.MainDocumentPart - - ' Assign a reference to the appropriate part to the - ' stylesPart variable. - Dim stylesPart As StylesPart = Nothing - ' Code removed here... - End Using -``` +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet3)] *** - --------------------------------------------------------------------------------- ## Find the Correct Styles Part The code next retrieves a reference to the requested styles part by -using the **getStylesWithEffectsPart** Boolean -parameter. Based on this value, the code retrieves a specific property -of the **docPart** variable, and stores it in the -**stylesPart** variable. +using the `getStylesWithEffectsPart` parameter. +Based on this value, the code retrieves a specific property +of the `docPart` variable, and stores it in the +`stylesPart` variable. ### [C#](#tab/cs-4) -```csharp - if (getStylesWithEffectsPart) - stylesPart = docPart.StylesWithEffectsPart; - else - stylesPart = docPart.StyleDefinitionsPart; -``` - +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-4) -```vb - If getStylesWithEffectsPart Then - stylesPart = docPart.StylesWithEffectsPart - Else - stylesPart = docPart.StyleDefinitionsPart - End If -``` +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet4)] *** @@ -210,40 +118,16 @@ of the **docPart** variable, and stores it in the ## Retrieve the Part Contents If the requested styles part exists, the code must return the contents -of the part in an **XDocument** instance. Each -part provides a [GetStream](/dotnet/api/documentformat.openxml.packaging.openxmlpart.getstream) method, which returns a Stream. -The code passes the Stream instance to the -[XmlNodeReader.Create](/dotnet/api/system.xml.xmlreader.create) -method, and then calls the -[XDocument.Load](/dotnet/api/system.xml.linq.xdocument.load) -method, passing the **XmlNodeReader** as a -parameter. +of the part in an `XDocument` instance. Each part provides a + method, which returns a Stream. +The code passes the Stream instance to the +method, and then calls the +method, passing the `XmlNodeReader` as a parameter. ### [C#](#tab/cs-5) -```csharp - // If the part exists, read it into the XDocument. - if (stylesPart != null) - { - using (var reader = XmlNodeReader.Create( - stylesPart.GetStream(FileMode.Open, FileAccess.Read))) - { - // Create the XDocument. - styles = XDocument.Load(reader); - } - } -``` - +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-5) -```vb - ' If the part exists, read it into the XDocument. - If stylesPart IsNot Nothing Then - Using reader = XmlNodeReader.Create( - stylesPart.GetStream(FileMode.Open, FileAccess.Read)) - ' Create the XDocument: - styles = XDocument.Load(reader) - End Using - End If -``` +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet5)] *** @@ -254,10 +138,10 @@ parameter. The following is the complete **ExtractStylesPart** code sample in C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs)] +[!code-csharp[](../../samples/word/extract_styles/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/extract_styles/vb/Program.vb)] +[!code-vb[](../../samples/word/extract_styles/vb/Program.vb#snippet)] --------------------------------------------------------------------------------- diff --git a/samples/word/extract_styles/cs/Program.cs b/samples/word/extract_styles/cs/Program.cs index 516e7c86..f7b9e2a5 100644 --- a/samples/word/extract_styles/cs/Program.cs +++ b/samples/word/extract_styles/cs/Program.cs @@ -1,29 +1,28 @@ +// using DocumentFormat.OpenXml.Packaging; using System; using System.IO; using System.Xml; using System.Xml.Linq; -if (args is [{ } fileName, { } getStyleWithEffectsPart]) -{ - ExtractStylesPart(fileName, getStyleWithEffectsPart); -} -else if (args is [{ } fileName2]) -{ - ExtractStylesPart(fileName2); -} // Extract the styles or stylesWithEffects part from a // word processing document as an XDocument instance. -static XDocument ExtractStylesPart(string fileName, string getStylesWithEffectsPart = "true") +// +static XDocument? ExtractStylesPart(string fileName, string getStylesWithEffectsPart = "true") +// { + // // Declare a variable to hold the XDocument. XDocument? styles = null; // Open the document for read access and get a reference. using (var document = WordprocessingDocument.Open(fileName, false)) { - if (document.MainDocumentPart is null || document.MainDocumentPart.StyleDefinitionsPart is null || document.MainDocumentPart.StylesWithEffectsPart is null) + if ( + document.MainDocumentPart is null || + (document.MainDocumentPart.StyleDefinitionsPart is null && document.MainDocumentPart.StylesWithEffectsPart is null) + ) { throw new ArgumentNullException("MainDocumentPart and/or one or both of the Styles parts is null."); } @@ -34,17 +33,51 @@ static XDocument ExtractStylesPart(string fileName, string getStylesWithEffectsP // Assign a reference to the appropriate part to the // stylesPart variable. StylesPart? stylesPart = null; + // + // if (getStylesWithEffectsPart.ToLower() == "true") + { stylesPart = docPart.StylesWithEffectsPart; + } else + { stylesPart = docPart.StyleDefinitionsPart; + } + // - using var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)); + // + if (stylesPart is not null) + { + using var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)); - // Create the XDocument. - styles = XDocument.Load(reader); + // Create the XDocument. + styles = XDocument.Load(reader); + } + // } // Return the XDocument instance. return styles; -} \ No newline at end of file +} +// + +// +if (args is [{ } fileName, { } getStyleWithEffectsPart]) +{ + var styles = ExtractStylesPart(fileName, getStyleWithEffectsPart); + + if (styles is not null) + { + Console.WriteLine(styles.ToString()); + } +} +else if (args is [{ } fileName2]) +{ + var styles = ExtractStylesPart(fileName2); + + if (styles is not null) + { + Console.WriteLine(styles.ToString()); + } +} +// diff --git a/samples/word/extract_styles/vb/Program.vb b/samples/word/extract_styles/vb/Program.vb index 6a182926..6926357f 100644 --- a/samples/word/extract_styles/vb/Program.vb +++ b/samples/word/extract_styles/vb/Program.vb @@ -1,19 +1,41 @@ +' Imports System.IO Imports System.Xml Imports DocumentFormat.OpenXml.Packaging Module Program Sub Main(args As String()) + ' + If args.Length >= 2 Then + Dim fileName As String = args(0) + Dim getStyleWithEffectsPart As String = args(1) + + Dim styles As XDocument = ExtractStylesPart(fileName, getStyleWithEffectsPart) + + If styles IsNot Nothing Then + Console.WriteLine(styles.ToString()) + End If + ElseIf args.Length = 1 Then + Dim fileName As String = args(0) + + Dim styles As XDocument = ExtractStylesPart(fileName) + + If styles IsNot Nothing Then + Console.WriteLine(styles.ToString()) + End If + End If + ' End Sub ' Extract the styles or stylesWithEffects part from a ' word processing document as an XDocument instance. - Public Function ExtractStylesPart( - ByVal fileName As String, - Optional ByVal getStylesWithEffectsPart As Boolean = True) As XDocument + ' + Public Function ExtractStylesPart(ByVal fileName As String, Optional ByVal getStylesWithEffectsPart As String = "true") As XDocument + ' + ' ' Declare a variable to hold the XDocument. Dim styles As XDocument = Nothing @@ -26,22 +48,30 @@ Module Program ' Assign a reference to the appropriate part to the ' stylesPart variable. Dim stylesPart As StylesPart = Nothing - If getStylesWithEffectsPart Then + ' + + ' + If getStylesWithEffectsPart.ToLower() = "true" Then stylesPart = docPart.StylesWithEffectsPart Else stylesPart = docPart.StyleDefinitionsPart End If + ' + ' ' If the part exists, read it into the XDocument. If stylesPart IsNot Nothing Then - Using reader = XmlNodeReader.Create( - stylesPart.GetStream(FileMode.Open, FileAccess.Read)) + Using reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)) + ' Create the XDocument: styles = XDocument.Load(reader) End Using End If End Using + ' + ' Return the XDocument instance. Return styles End Function -End Module \ No newline at end of file +End Module +' From 367e9343951c38a41b881d6a2169373194bf1b3c Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Fri, 9 Feb 2024 15:42:28 -0800 Subject: [PATCH 09/53] closes #214 --- ...ic-author-in-a-word-processing-document.md | 258 ++++-------------- .../cs/Program.cs | 76 ++++-- .../vb/Program.vb | 77 ++++-- 3 files changed, 161 insertions(+), 250 deletions(-) diff --git a/docs/word/how-to-delete-comments-by-all-or-a-specific-author-in-a-word-processing-document.md b/docs/word/how-to-delete-comments-by-all-or-a-specific-author-in-a-word-processing-document.md index c8ee6ffa..c2bcc55f 100644 --- a/docs/word/how-to-delete-comments-by-all-or-a-specific-author-in-a-word-processing-document.md +++ b/docs/word/how-to-delete-comments-by-all-or-a-specific-author-in-a-word-processing-document.md @@ -12,7 +12,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 02/09/2024 ms.localizationpriority: medium --- # Delete comments by all or a specific author in a word processing document @@ -20,7 +20,7 @@ ms.localizationpriority: medium This topic shows how to use the classes in the Open XML SDK for Office to programmatically delete comments by all or a specific author in a word processing document, without having to load the document into -Microsoft Word. It contains an example **DeleteComments** method to illustrate this task. +Microsoft Word. It contains an example `DeleteComments` method to illustrate this task. @@ -28,7 +28,7 @@ Microsoft Word. It contains an example **DeleteComments** method to illustrate t ## DeleteComments Method -You can use the **DeleteComments** method to +You can use the `DeleteComments` method to delete all of the comments from a word processing document, or only those written by a specific author. As shown in the following code, the method accepts two parameters that indicate the name of the document to @@ -38,20 +38,9 @@ deletes comments written by the specified author. If you do not supply an author name, the code deletes all comments. ### [C#](#tab/cs-0) -```csharp - // Delete comments by a specific author. Pass an empty string for the - // author to delete all comments, by all authors. - public static void DeleteComments(string fileName, - string author = "") -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - ' Delete comments by a specific author. Pass an empty string for the author - ' to delete all comments, by all authors. - Public Sub DeleteComments(ByVal fileName As String, - Optional ByVal author As String = "") -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet1)] *** @@ -59,73 +48,33 @@ an author name, the code deletes all comments. ## Calling the DeleteComments Method -To call the **DeleteComments** method, provide +To call the `DeleteComments` method, provide the required parameters as shown in the following code. ### [C#](#tab/cs-1) -```csharp - DeleteComments(@"C:\Users\Public\Documents\DeleteComments.docx", - "David Jones"); -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - DeleteComments("C:\Users\Public\Documents\DeleteComments.docx", - "David Jones") -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet2)] *** -------------------------------------------------------------------------------- ## How the Code Works -The following code starts by opening the document, using the [WordprocessingDocument.Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method and -indicating that the document should be open for read/write access (the -final **true** parameter value). Next, the code -retrieves a reference to the comments part, using the [WordprocessingCommentsPart](/dotnet/api/documentformat.openxml.packaging.maindocumentpart.wordprocessingcommentspart) property of the -main document part, after having retrieved a reference to the main -document part from the [MainDocumentPart](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.maindocumentpart) property of the word -processing document. If the comments part is missing, there is no point + +The following code starts by opening the document, using the + +method and indicating that the document should be open for read/write access (the +final `true` parameter value). Next, the code retrieves a reference to the comments +part, using the +property of the main document part, after having retrieved a reference to the main +document part from the +property of the word processing document. If the comments part is missing, there is no point in proceeding, as there cannot be any comments to delete. ### [C#](#tab/cs-2) -```csharp - // Get an existing Wordprocessing document. - using (WordprocessingDocument document = - WordprocessingDocument.Open(fileName, true)) - { - // Set commentPart to the document WordprocessingCommentsPart, - // if it exists. - WordprocessingCommentsPart commentPart = - document.MainDocumentPart.WordprocessingCommentsPart; - - // If no WordprocessingCommentsPart exists, there can be no - // comments. Stop execution and return from the method. - if (commentPart == null) - { - return; - } - // Code removed here… - } -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Get an existing Wordprocessing document. - Using document As WordprocessingDocument = - WordprocessingDocument.Open(fileName, True) - ' Set commentPart to the document - ' WordprocessingCommentsPart, if it exists. - Dim commentPart As WordprocessingCommentsPart = - document.MainDocumentPart.WordprocessingCommentsPart - - ' If no WordprocessingCommentsPart exists, there can be no - ' comments. Stop execution and return from the method. - If (commentPart Is Nothing) Then - Return - End If - ' Code removed here… - End Using -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet3)] *** @@ -138,64 +87,40 @@ delete, and creating a list of comment IDs that correspond to the comments to delete. Given these lists, the code can both delete the comments from the comments part that contains the comments, and delete the references to the comments from the document part.The following code -starts by retrieving a list of [Comment](/dotnet/api/documentformat.openxml.wordprocessing.comment) elements. To retrieve the list, it -converts the [Elements](/dotnet/api/documentformat.openxml.openxmlelement.elements) collection exposed by the **commentPart** variable into a list of **Comment** objects. +starts by retrieving a list of +elements. To retrieve the list, it converts the +collection exposed by the `commentPart` variable into a list of `Comment` objects. ### [C#](#tab/cs-3) -```csharp - List commentsToDelete = - commentPart.Comments.Elements().ToList(); -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - Dim commentsToDelete As List(Of Comment) = _ - commentPart.Comments.Elements(Of Comment)().ToList() -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet4)] *** So far, the list of comments contains all of the comments. If the author parameter is not an empty string, the following code limits the list to -only those comments where the [Author](/dotnet/api/documentformat.openxml.wordprocessing.comment.author) property matches the parameter you -supplied. +only those comments where the +property matches the parameter you supplied. ### [C#](#tab/cs-4) -```csharp - if (!String.IsNullOrEmpty(author)) - { - commentsToDelete = commentsToDelete. - Where(c => c.Author == author).ToList(); - } -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - If Not String.IsNullOrEmpty(author) Then - commentsToDelete = commentsToDelete. - Where(Function(c) c.Author = author).ToList() - End If -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet5)] *** Before deleting any comments, the code retrieves a list of comments ID values, so that it can later delete matching elements from the document -part. The call to the [Select](/dotnet/api/system.linq.enumerable.select) -method effectively projects the list of comments, retrieving an [IEnumerable\](/dotnet/api/system.collections.generic.ienumerable-1) -of strings that contain all the comment ID values. +part. The call to the +method effectively projects the list of comments, retrieving an + of strings that +contain all the comment ID values. ### [C#](#tab/cs-5) -```csharp - IEnumerable commentIds = - commentsToDelete.Select(r => r.Id.Value); -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - Dim commentIds As IEnumerable(Of String) = - commentsToDelete.Select(Function(r) r.Id.Value) -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet6)] *** @@ -203,34 +128,14 @@ of strings that contain all the comment ID values. ## Deleting Comments and Saving the Part -Given the **commentsToDelete** collection, to +Given the `commentsToDelete` collection, to the following code loops through all the comments that require deleting and performs the deletion. The code then saves the comments part. ### [C#](#tab/cs-6) -```csharp - // Delete each comment in commentToDelete from the - // Comments collection. - foreach (Comment c in commentsToDelete) - { - c.Remove(); - } - - // Save the comment part changes. - commentPart.Comments.Save(); -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - ' Delete each comment in commentToDelete from the Comments - ' collection. - For Each c As Comment In commentsToDelete - c.Remove() - Next - - ' Save the comment part changes. - commentPart.Comments.Save() -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet7)] *** @@ -241,10 +146,13 @@ and performs the deletion. The code then saves the comments part. Although the code has successfully removed all the comments by this point, that is not enough. The code must also remove references to the comments from the document part. This action requires three steps -because the comment reference includes the [CommentRangeStart](/dotnet/api/documentformat.openxml.wordprocessing.commentrangestart), [CommentRangeEnd](/dotnet/api/documentformat.openxml.wordprocessing.commentrangeend), and [CommentReference](/dotnet/api/documentformat.openxml.wordprocessing.commentreference) elements, and the code -must remove all three for each comment. Before performing any deletions, -the code first retrieves a reference to the root element of the main -document part, as shown in the following code. +because the comment reference includes the +, +, +and +elements, and the code must remove all three for each comment. +Before performing any deletions, the code first retrieves a reference +to the root element of the main document part, as shown in the following code. ### [C#](#tab/cs-7) ```csharp @@ -261,76 +169,16 @@ document part, as shown in the following code. Given a reference to the document element, the following code performs its deletion loop three times, once for each of the different elements it must delete. In each case, the code looks for all descendants of the -correct type (**CommentRangeStart**, **CommentRangeEnd**, or **CommentReference**) and limits the list to those -whose [Id](/dotnet/api/documentformat.openxml.wordprocessing.markuprangetype.id) property value is contained in the list -of comment IDs to be deleted. Given the list of elements to be deleted, -the code removes each element in turn. Finally, the code completes by -saving the document. +correct type (`CommentRangeStart`, `CommentRangeEnd`, or `CommentReference`) +and limits the list to those whose +property value is contained in the list of comment IDs to be deleted. +Given the list of elements to be deleted, the code removes each element in turn. +Finally, the code completes by saving the document. ### [C#](#tab/cs-8) -```csharp - // Delete CommentRangeStart for each - // deleted comment in the main document. - List commentRangeStartToDelete = - doc.Descendants(). - Where(c => commentIds.Contains(c.Id.Value)).ToList(); - foreach (CommentRangeStart c in commentRangeStartToDelete) - { - c.Remove(); - } - - // Delete CommentRangeEnd for each deleted comment in the main document. - List commentRangeEndToDelete = - doc.Descendants(). - Where(c => commentIds.Contains(c.Id.Value)).ToList(); - foreach (CommentRangeEnd c in commentRangeEndToDelete) - { - c.Remove(); - } - - // Delete CommentReference for each deleted comment in the main document. - List commentRangeReferenceToDelete = - doc.Descendants(). - Where(c => commentIds.Contains(c.Id.Value)).ToList(); - foreach (CommentReference c in commentRangeReferenceToDelete) - { - c.Remove(); - } - - // Save changes back to the MainDocumentPart part. - doc.Save(); -``` - +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet9)] ### [Visual Basic](#tab/vb-8) -```vb - ' Delete CommentRangeStart for each - ' deleted comment in the main document. - Dim commentRangeStartToDelete As List(Of CommentRangeStart) = _ - doc.Descendants(Of CommentRangeStart). _ - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList() - For Each c As CommentRangeStart In commentRangeStartToDelete - c.Remove() - Next - - ' Delete CommentRangeEnd for each deleted comment in the main document. - Dim commentRangeEndToDelete As List(Of CommentRangeEnd) = _ - doc.Descendants(Of CommentRangeEnd). _ - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList() - For Each c As CommentRangeEnd In commentRangeEndToDelete - c.Remove() - Next - - ' Delete CommentReference for each deleted comment in the main document. - Dim commentRangeReferenceToDelete As List(Of CommentReference) = _ - doc.Descendants(Of CommentReference). _ - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList - For Each c As CommentReference In commentRangeReferenceToDelete - c.Remove() - Next - - ' Save changes back to the MainDocumentPart part. - doc.Save() -``` +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet9)] *** @@ -341,10 +189,10 @@ saving the document. The following is the complete code sample in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs)] +[!code-csharp[](../../samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb)] +[!code-vb[](../../samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb#snippet)] -------------------------------------------------------------------------------- diff --git a/samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs b/samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs index 80cbae92..320386d9 100644 --- a/samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs +++ b/samples/word/delete_comments_by_all_or_a_specific_author/cs/Program.cs @@ -1,28 +1,30 @@ +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Collections.Generic; using System.Linq; -DeleteComments(args[0], args[1]); +// // Delete comments by a specific author. Pass an empty string for the // author to delete all comments, by all authors. static void DeleteComments(string fileName, string author = "") +// { + // // Get an existing Wordprocessing document. using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true)) { - if (document.MainDocumentPart is null || document.MainDocumentPart.WordprocessingCommentsPart is null) + if (document.MainDocumentPart is null) { - throw new ArgumentNullException("MainDocumentPart and/or WordprocessingCommentsPart is null."); + throw new ArgumentNullException("MainDocumentPart is null."); } // Set commentPart to the document WordprocessingCommentsPart, // if it exists. - WordprocessingCommentsPart commentPart = - document.MainDocumentPart.WordprocessingCommentsPart; + WordprocessingCommentsPart? commentPart = document.MainDocumentPart.WordprocessingCommentsPart; // If no WordprocessingCommentsPart exists, there can be no // comments. Stop execution and return from the method. @@ -30,54 +32,71 @@ static void DeleteComments(string fileName, string author = "") { return; } + // // Create a list of comments by the specified author, or // if the author name is empty, all authors. - List commentsToDelete = - commentPart.Comments.Elements().ToList(); + // + List commentsToDelete = commentPart.Comments.Elements().ToList(); + // + + // if (!String.IsNullOrEmpty(author)) { - commentsToDelete = commentsToDelete. - Where(c => c.Author == author).ToList(); + commentsToDelete = commentsToDelete.Where(c => c.Author == author).ToList(); } - IEnumerable commentIds = - commentsToDelete.Where(r => r.Id is not null && r.Id.HasValue).Select(r => r.Id?.Value); + // + + // + IEnumerable commentIds = commentsToDelete.Where(r => r.Id is not null && r.Id.HasValue).Select(r => r.Id?.Value); + // + // // Delete each comment in commentToDelete from the // Comments collection. foreach (Comment c in commentsToDelete) { - c.Remove(); + if (c is not null) + { + c.Remove(); + } } // Save the comment part change. commentPart.Comments.Save(); + // + // Document doc = document.MainDocumentPart.Document; + // + // // Delete CommentRangeStart for each // deleted comment in the main document. - List commentRangeStartToDelete = - doc.Descendants(). - Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList(); + List commentRangeStartToDelete = doc.Descendants() + .Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)) + .ToList(); + foreach (CommentRangeStart c in commentRangeStartToDelete) { c.Remove(); } // Delete CommentRangeEnd for each deleted comment in the main document. - List commentRangeEndToDelete = - doc.Descendants(). - Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList(); + List commentRangeEndToDelete = doc.Descendants() + .Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)) + .ToList(); + foreach (CommentRangeEnd c in commentRangeEndToDelete) { c.Remove(); } // Delete CommentReference for each deleted comment in the main document. - List commentRangeReferenceToDelete = - doc.Descendants(). - Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)).ToList(); + List commentRangeReferenceToDelete = doc.Descendants() + .Where(c => c.Id is not null && c.Id.HasValue && commentIds.Contains(c.Id.Value)) + .ToList(); + foreach (CommentReference c in commentRangeReferenceToDelete) { c.Remove(); @@ -85,5 +104,18 @@ static void DeleteComments(string fileName, string author = "") // Save changes back to the MainDocumentPart part. doc.Save(); + // } -} \ No newline at end of file +} +// + +// +if (args is [{ } fileName, { } author]) +{ + DeleteComments(fileName, author); +} +else if (args is [{ } fileName2]) +{ + DeleteComments(fileName2); +} +// diff --git a/samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb b/samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb index 59deeb07..5e7cc1fd 100644 --- a/samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb +++ b/samples/word/delete_comments_by_all_or_a_specific_author/vb/Program.vb @@ -1,79 +1,110 @@ +' Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing Module Program Sub Main(args As String()) + ' + If (args.Length >= 2) Then + Dim fileName As String = args(0) + Dim author As String = args(1) + + DeleteComments(fileName, author) + ElseIf args.Length = 1 Then + Dim fileName As String = args(0) + + DeleteComments(fileName) + End If + ' End Sub + ' ' Delete comments by a specific author. Pass an empty string for the author ' to delete all comments, by all authors. - Public Sub DeleteComments(ByVal fileName As String, - Optional ByVal author As String = "") + Public Sub DeleteComments(ByVal fileName As String, Optional ByVal author As String = "") + ' + ' ' Get an existing Wordprocessing document. - Using document As WordprocessingDocument = - WordprocessingDocument.Open(fileName, True) + Using document As WordprocessingDocument = WordprocessingDocument.Open(fileName, True) ' Set commentPart to the document ' WordprocessingCommentsPart, if it exists. - Dim commentPart As WordprocessingCommentsPart = - document.MainDocumentPart.WordprocessingCommentsPart + Dim commentPart As WordprocessingCommentsPart = document.MainDocumentPart.WordprocessingCommentsPart ' If no WordprocessingCommentsPart exists, there can be no ' comments. Stop execution and return from the method. If (commentPart Is Nothing) Then Return End If + ' ' Create a list of comments by the specified author, or ' if the author name is empty, all authors. - Dim commentsToDelete As List(Of Comment) = - commentPart.Comments.Elements(Of Comment)().ToList() + ' + Dim commentsToDelete As List(Of Comment) = commentPart.Comments.Elements(Of Comment)().ToList() + ' + + ' If Not String.IsNullOrEmpty(author) Then - commentsToDelete = commentsToDelete. - Where(Function(c) c.Author = author).ToList() + commentsToDelete = commentsToDelete.Where(Function(c) c.Author = author).ToList() End If - Dim commentIds As IEnumerable(Of String) = - commentsToDelete.Select(Function(r) r.Id.Value) + ' + + ' + Dim commentIds As IEnumerable(Of String) = commentsToDelete.Where(Function(r) r IsNot Nothing And r.Id.HasValue).Select(Function(r) r.Id.Value) + ' + ' ' Delete each comment in commentToDelete from the Comments ' collection. For Each c As Comment In commentsToDelete - c.Remove() + If (c IsNot Nothing) Then + c.Remove() + End If Next ' Save the comment part change. commentPart.Comments.Save() + ' + ' Dim doc As Document = document.MainDocumentPart.Document + ' + ' ' Delete CommentRangeStart for each ' deleted comment in the main document. - Dim commentRangeStartToDelete As List(Of CommentRangeStart) = - doc.Descendants(Of CommentRangeStart). - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList() + Dim commentRangeStartToDelete As List(Of CommentRangeStart) = doc.Descendants(Of CommentRangeStart). + Where(Function(c) commentIds.Contains(c.Id.Value)). + ToList() + For Each c As CommentRangeStart In commentRangeStartToDelete c.Remove() Next ' Delete CommentRangeEnd for each deleted comment in main document. - Dim commentRangeEndToDelete As List(Of CommentRangeEnd) = - doc.Descendants(Of CommentRangeEnd). - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList() + Dim commentRangeEndToDelete As List(Of CommentRangeEnd) = doc.Descendants(Of CommentRangeEnd). + Where(Function(c) commentIds.Contains(c.Id.Value)). + ToList() + For Each c As CommentRangeEnd In commentRangeEndToDelete c.Remove() Next ' Delete CommentReference for each deleted comment in the main document. - Dim commentRangeReferenceToDelete As List(Of CommentReference) = - doc.Descendants(Of CommentReference). - Where(Function(c) commentIds.Contains(c.Id.Value)).ToList + Dim commentRangeReferenceToDelete As List(Of CommentReference) = doc.Descendants(Of CommentReference). + Where(Function(c) commentIds.Contains(c.Id.Value)). + ToList() + For Each c As CommentReference In commentRangeReferenceToDelete c.Remove() Next ' Save changes back to the MainDocumentPart part. doc.Save() + ' End Using End Sub -End Module \ No newline at end of file +End Module +' From a37abb3ff173f26b758a454b5f0e7145b28d229b Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Tue, 13 Feb 2024 10:59:36 -0800 Subject: [PATCH 10/53] closes #213 --- ...aph-style-to-a-word-processing-document.md | 347 ++---------------- .../cs/Program.cs | 210 +++++++---- .../vb/Program.vb | 71 +++- 3 files changed, 250 insertions(+), 378 deletions(-) diff --git a/docs/word/how-to-create-and-add-a-paragraph-style-to-a-word-processing-document.md b/docs/word/how-to-create-and-add-a-paragraph-style-to-a-word-processing-document.md index 1ec0f0f8..6d541628 100644 --- a/docs/word/how-to-create-and-add-a-paragraph-style-to-a-word-processing-document.md +++ b/docs/word/how-to-create-and-add-a-paragraph-style-to-a-word-processing-document.md @@ -12,7 +12,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 02/13/2024 ms.localizationpriority: high --- # Create and add a paragraph style to a word processing document @@ -20,7 +20,7 @@ ms.localizationpriority: high This topic shows how to use the classes in the Open XML SDK for Office to programmatically create and add a paragraph style to a word processing document. It contains an example -**CreateAndAddParagraphStyle** method to illustrate this task, plus a +`CreateAndAddParagraphStyle` method to illustrate this task, plus a supplemental example method to add the styles part when necessary. @@ -29,7 +29,7 @@ supplemental example method to add the styles part when necessary. ## CreateAndAddParagraphStyle Method -The **CreateAndAddParagraphStyle** sample method can be used to add a +The `CreateAndAddParagraphStyle` sample method can be used to add a style to a word processing document. You must first obtain a reference to the style definitions part in the document to which you want to add the style. For more information and an example of how to do this, see @@ -43,16 +43,9 @@ interface), and optionally, any style aliases (alternate names for use in the user interface). ### [C#](#tab/cs-0) -```csharp - public static void CreateAndAddParagraphStyle(StyleDefinitionsPart styleDefinitionsPart, - string styleid, string stylename, string aliases="") -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Sub CreateAndAddParagraphStyle(ByVal styleDefinitionsPart As StyleDefinitionsPart, - ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet1)] *** @@ -75,7 +68,7 @@ For example, consider the following XML code example taken from a style definition. ```xml - . . . @@ -94,125 +87,23 @@ application. ## Calling the Sample Method -Use the **CreateAndAddParagraphStyle** example +Use the `CreateAndAddParagraphStyle` example method to create and add a named style to a word processing document using the Open XML SDK. The following code example shows how to open and obtain a reference to a word processing document, retrieve a reference -to the style definitions part of the document, and then call the **CreateAndAddParagraphStyle** method. +to the style definitions part of the document, and then call the `CreateAndAddParagraphStyle` method. To call the method, pass a reference to the style definitions part as the first parameter, the style ID of the style as the second parameter, the name of the style as the third parameter, and optionally, any style aliases as the fourth parameter. For example, the following code creates -the "Overdue Amount Para" paragraph style in a sample file that is named -CreateAndAddParagraphStyle.docx. It also adds a paragraph of text, and +the "Overdue Amount Para" paragraph style. It also adds a paragraph of text, and applies the style to the paragraph. ### [C#](#tab/cs-1) -```csharp - string strDoc = @"C:\Users\Public\Documents\CreateAndAddParagraphStyle.docx"; - - using (WordprocessingDocument doc = - WordprocessingDocument.Open(strDoc, true)) - { - // Get the Styles part for this document. - StyleDefinitionsPart part = - doc.MainDocumentPart.StyleDefinitionsPart; - - // If the Styles part does not exist, add it and then add the style. - if (part == null) - { - part = AddStylesPartToPackage(doc); - } - - // Set up a variable to hold the style ID. - string parastyleid = "OverdueAmountPara"; - - // Create and add a paragraph style to the specified styles part - // with the specified style ID, style name and aliases. - CreateAndAddParagraphStyle(part, - parastyleid, - "Overdue Amount Para", - "Late Due, Late Amount"); - - // Add a paragraph with a run and some text. - Paragraph p = - new Paragraph( - new Run( - new Text("This is some text in a run in a paragraph."))); - - // Add the paragraph as a child element of the w:body element. - doc.MainDocumentPart.Document.Body.AppendChild(p); - - // If the paragraph has no ParagraphProperties object, create one. - if (p.Elements().Count() == 0) - { - p.PrependChild(new ParagraphProperties()); - } - - // Get a reference to the ParagraphProperties object. - ParagraphProperties pPr = p.ParagraphProperties; - - // If a ParagraphStyleId object doesn't exist, create one. - if (pPr.ParagraphStyleId == null) - pPr.ParagraphStyleId = new ParagraphStyleId(); - - // Set the style of the paragraph. - pPr.ParagraphStyleId.Val = parastyleid; - } -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim strDoc As String = "C:\Users\Public\Documents\CreateAndAddParagraphStyle.docx" - - Using doc As WordprocessingDocument = - WordprocessingDocument.Open(strDoc, True) - - ' Get the Styles part for this document. - Dim part As StyleDefinitionsPart = - doc.MainDocumentPart.StyleDefinitionsPart - - ' If the Styles part does not exist, add it. - If part Is Nothing Then - part = AddStylesPartToPackage(doc) - End If - - ' Set up a variable to hold the style ID. - Dim parastyleid As String = "OverdueAmountPara" - - ' Create and add a paragraph style to the specified styles part - ' with the specified style ID, style name and aliases. - CreateAndAddParagraphStyle(part, - parastyleid, - "Overdue Amount Para", - "Late Due, Late Amount") - - ' Add a paragraph with a run and some text. - Dim p As New Paragraph( - New Run( - New Text("This is some text in a run in a paragraph."))) - - ' Add the paragraph as a child element of the w:body element. - doc.MainDocumentPart.Document.Body.AppendChild(p) - - ' If the paragraph has no ParagraphProperties object, create one. - If p.Elements(Of ParagraphProperties)().Count() = 0 Then - p.PrependChild(Of ParagraphProperties)(New ParagraphProperties()) - End If - - ' Get a reference to the ParagraphProperties object. - Dim pPr As ParagraphProperties = p.ParagraphProperties - - ' If a ParagraphStyleId object doesn't exist, create one. - If pPr.ParagraphStyleId Is Nothing Then - pPr.ParagraphStyleId = New ParagraphStyleId() - End If - - ' Set the style of the paragraph. - pPr.ParagraphStyleId.Val = parastyleid - End Using -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet2)] *** @@ -315,32 +206,16 @@ styleId attribute value for this style in the paragraph properties' ## How the Code Works -The **CreateAndAddParagraphStyle** method +The `CreateAndAddParagraphStyle` method begins by retrieving a reference to the styles element in the styles part. The styles element is the root element of the part and contains all of the individual style elements. If the reference is null, the styles element is created and saved to the part. ### [C#](#tab/cs-2) -```csharp - // Access the root element of the styles part. - Styles styles = styleDefinitionsPart.Styles; - if (styles == null) - { - styleDefinitionsPart.Styles = new Styles(); - styleDefinitionsPart.Styles.Save(); - } -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Access the root element of the styles part. - Dim styles As Styles = styleDefinitionsPart.Styles - If styles Is Nothing Then - styleDefinitionsPart.Styles = New Styles() - styleDefinitionsPart.Styles.Save() - End If -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet3)] *** @@ -348,28 +223,16 @@ styles element is created and saved to the part. ## Creating the Style -To create the style, the code instantiates the **[Style](/dotnet/api/documentformat.openxml.wordprocessing.style)** class and sets certain properties, -such as the **[Type](/dotnet/api/documentformat.openxml.wordprocessing.style.type)** of style (paragraph), the **[StyleId](/dotnet/api/documentformat.openxml.wordprocessing.style.styleid)**, whether the style is a **[CustomStyle](/dotnet/api/documentformat.openxml.wordprocessing.style.customstyle)**, and whether the style is the -**[Default](/dotnet/api/documentformat.openxml.wordprocessing.style.default)** style for its type. +To create the style, the code instantiates the +class and sets certain properties, such as the +of style (paragraph), the , whether the +style is a , and whether the style is the + style for its type. ### [C#](#tab/cs-3) -```csharp - // Create a new paragraph style element and specify some of the attributes. - Style style = new Style() { Type = StyleValues.Paragraph, - StyleId = styleid, - CustomStyle = true, - Default = false - }; -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' Create a new paragraph style element and specify some of the attributes. - Dim style As New Style() With { .Type = StyleValues.Paragraph, _ - .StyleId = styleid, _ - .CustomStyle = True, _ - .[Default] = False} -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet4)] *** @@ -384,128 +247,29 @@ The code results in the following XML. The code next creates the child elements of the style, which define the properties of the style. To create an element, you instantiate its -corresponding class, and then call the **[Append([])](/dotnet/api/documentformat.openxml.openxmlelement.append)** method add the child element to -the style. For more information about these properties, see section 17.7 -of the [!include[ISO/IEC 29500 URL](../includes/iso-iec-29500-link.md)] +corresponding class, and then call the +method add the child element to the style. For more information about these properties, +see section 17.7 of the [!include[ISO/IEC 29500 URL](../includes/iso-iec-29500-link.md)] specification. ### [C#](#tab/cs-4) -```csharp - // Create and add the child elements (properties of the style). - Aliases aliases1 = new Aliases() { Val = aliases }; - AutoRedefine autoredefine1 = new AutoRedefine() { Val = OnOffOnlyValues.Off }; - BasedOn basedon1 = new BasedOn() { Val = "Normal" }; - LinkedStyle linkedStyle1 = new LinkedStyle() { Val = "OverdueAmountChar" }; - Locked locked1 = new Locked() { Val = OnOffOnlyValues.Off }; - PrimaryStyle primarystyle1 = new PrimaryStyle() { Val = OnOffOnlyValues.On }; - StyleHidden stylehidden1 = new StyleHidden() { Val = OnOffOnlyValues.Off }; - SemiHidden semihidden1 = new SemiHidden() { Val = OnOffOnlyValues.Off }; - StyleName styleName1 = new StyleName() { Val = stylename }; - NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" }; - UIPriority uipriority1 = new UIPriority() { Val = 1 }; - UnhideWhenUsed unhidewhenused1 = new UnhideWhenUsed() { Val = OnOffOnlyValues.On }; - if (aliases != "") - style.Append(aliases1); - style.Append(autoredefine1); - style.Append(basedon1); - style.Append(linkedStyle1); - style.Append(locked1); - style.Append(primarystyle1); - style.Append(stylehidden1); - style.Append(semihidden1); - style.Append(styleName1); - style.Append(nextParagraphStyle1); - style.Append(uipriority1); - style.Append(unhidewhenused1); -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - ' Create and add the child elements (properties of the style) - Dim aliases1 As New Aliases() With {.Val = aliases} - Dim autoredefine1 As New AutoRedefine() With {.Val = OnOffOnlyValues.Off} - Dim basedon1 As New BasedOn() With {.Val = "Normal"} - Dim linkedStyle1 As New LinkedStyle() With {.Val = "OverdueAmountChar"} - Dim locked1 As New Locked() With {.Val = OnOffOnlyValues.Off} - Dim primarystyle1 As New PrimaryStyle() With {.Val = OnOffOnlyValues.[On]} - Dim stylehidden1 As New StyleHidden() With {.Val = OnOffOnlyValues.Off} - Dim semihidden1 As New SemiHidden() With {.Val = OnOffOnlyValues.Off} - Dim styleName1 As New StyleName() With {.Val = stylename} - Dim nextParagraphStyle1 As New NextParagraphStyle() With { _ - .Val = "Normal"} - Dim uipriority1 As New UIPriority() With {.Val = 1} - Dim unhidewhenused1 As New UnhideWhenUsed() With { _ - .Val = OnOffOnlyValues.[On]} - If aliases <> "" Then - style.Append(aliases1) - End If - style.Append(autoredefine1) - style.Append(basedon1) - style.Append(linkedStyle1) - style.Append(locked1) - style.Append(primarystyle1) - style.Append(stylehidden1) - style.Append(semihidden1) - style.Append(styleName1) - style.Append(nextParagraphStyle1) - style.Append(uipriority1) - style.Append(unhidewhenused1) -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet5)] *** -Next, the code instantiates a **[StyleRunProperties](/dotnet/api/documentformat.openxml.wordprocessing.stylerunproperties)** object to create a **rPr** (Run Properties) element. You specify the character properties that apply to the style, such as font and color, in this element. The properties are then appended as children of the **rPr** element. +Next, the code instantiates a +object to create a `rPr` (Run Properties) element. You specify the character properties that +apply to the style, such as font and color, in this element. The properties are then appended +as children of the `rPr` element. -When the run properties are created, the code appends the **rPr** element to the style, and the style element to the styles root element in the styles part. +When the run properties are created, the code appends the `rPr` element to the style, and the style element to the styles root element in the styles part. ### [C#](#tab/cs-5) -```csharp - // Create the StyleRunProperties object and specify some of the run properties. - StyleRunProperties styleRunProperties1 = new StyleRunProperties(); - Bold bold1 = new Bold(); - Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 }; - RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" }; - Italic italic1 = new Italic(); - // Specify a 12 point size. - FontSize fontSize1 = new FontSize() { Val = "24" }; - styleRunProperties1.Append(bold1); - styleRunProperties1.Append(color1); - styleRunProperties1.Append(font1); - styleRunProperties1.Append(fontSize1); - styleRunProperties1.Append(italic1); - - // Add the run properties to the style. - style.Append(styleRunProperties1); - - // Add the style to the styles part. - styles.Append(style); -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - ' Create the StyleRunProperties object and specify some of the run properties. - Dim styleRunProperties1 As New StyleRunProperties() - Dim bold1 As New Bold() - Dim color1 As New Color() With { _ - .ThemeColor = ThemeColorValues.Accent2} - Dim font1 As New RunFonts() With { _ - .Ascii = "Lucida Console"} - Dim italic1 As New Italic() - ' Specify a 12 point size. - Dim fontSize1 As New FontSize() With { _ - .Val = "24"} - styleRunProperties1.Append(bold1) - styleRunProperties1.Append(color1) - styleRunProperties1.Append(font1) - styleRunProperties1.Append(fontSize1) - styleRunProperties1.Append(italic1) - - ' Add the run properties to the style. - style.Append(styleRunProperties1) - - ' Add the style to the styles part. - styles.Append(style) -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet6)] *** @@ -518,45 +282,12 @@ referencing the styleId attribute value for this style in the paragraph properties' pStyle element. The following code example shows how to apply a style to a paragraph referenced by the variable p. The style ID of the style to apply is stored in the parastyleid variable, and the -ParagraphStyleId property represents the paragraph properties' **pStyle** element. +ParagraphStyleId property represents the paragraph properties' `pStyle` element. ### [C#](#tab/cs-6) -```csharp - // If the paragraph has no ParagraphProperties object, create one. - if (p.Elements().Count() == 0) - { - p.PrependChild(new ParagraphProperties()); - } - - // Get a reference to the ParagraphProperties object. - ParagraphProperties pPr = p.ParagraphProperties; - - // If a ParagraphStyleId object does not exist, create one. - if (pPr.ParagraphStyleId == null) - pPr.ParagraphStyleId = new ParagraphStyleId(); - - // Set the style of the paragraph. - pPr.ParagraphStyleId.Val = parastyleid; -``` - +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - ' If the paragraph has no ParagraphProperties object, create one. - If p.Elements(Of ParagraphProperties)().Count() = 0 Then - p.PrependChild(Of ParagraphProperties)(New ParagraphProperties()) - End If - - ' Get a reference to the ParagraphProperties object. - Dim pPr As ParagraphProperties = p.ParagraphProperties - - ' If a ParagraphStyleId object does not exist, create one. - If pPr.ParagraphStyleId Is Nothing Then - pPr.ParagraphStyleId = New ParagraphStyleId() - End If - - ' Set the style of the paragraph. - pPr.ParagraphStyleId.Val = parastyleid -``` +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet7)] *** @@ -564,14 +295,14 @@ ParagraphStyleId property represents the paragraph properties' **pStyle** elemen ## Sample Code -The following is the complete **CreateAndAddParagraphStyle** code sample in both +The following is the complete `CreateAndAddParagraphStyle` code sample in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs)] +[!code-csharp[](../../samples/word/create_and_add_a_paragraph_style/cs/Program.cs#snippet)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb)] +[!code-vb[](../../samples/word/create_and_add_a_paragraph_style/vb/Program.vb#snippet)] --------------------------------------------------------------------------------- diff --git a/samples/word/create_and_add_a_paragraph_style/cs/Program.cs b/samples/word/create_and_add_a_paragraph_style/cs/Program.cs index 2d605ff1..1b0fc280 100644 --- a/samples/word/create_and_add_a_paragraph_style/cs/Program.cs +++ b/samples/word/create_and_add_a_paragraph_style/cs/Program.cs @@ -1,78 +1,95 @@ +// using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; +using System.Linq; -CreateAndAddParagraphStyle(args[0], args[1], args[2], args[3]); // Create a new paragraph style with the specified style ID, primary style name, and aliases and // add it to the specified style definitions part. -static void CreateAndAddParagraphStyle(string filePath, string styleid, string stylename, string aliases = "") +// +static void CreateAndAddParagraphStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename, string aliases = "") +// { - using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filePath, true)) + // + // Access the root element of the styles part. + Styles? styles = styleDefinitionsPart.Styles; + + if (styles is null) { - // Access the root element of the styles part. - Styles? styles = wordprocessingDocument?.MainDocumentPart?.StyleDefinitionsPart?.Styles ?? AddStylesPartToPackage(wordprocessingDocument).Styles; - - if (styles is not null) - { - - // Create a new paragraph style element and specify some of the attributes. - Style style = new Style() - { - Type = StyleValues.Paragraph, - StyleId = styleid, - CustomStyle = true, - Default = false - }; - - // Create and add the child elements (properties of the style). - Aliases aliases1 = new Aliases() { Val = aliases }; - AutoRedefine autoredefine1 = new AutoRedefine() { Val = OnOffOnlyValues.Off }; - BasedOn basedon1 = new BasedOn() { Val = "Normal" }; - LinkedStyle linkedStyle1 = new LinkedStyle() { Val = "OverdueAmountChar" }; - Locked locked1 = new Locked() { Val = OnOffOnlyValues.Off }; - PrimaryStyle primarystyle1 = new PrimaryStyle() { Val = OnOffOnlyValues.On }; - StyleHidden stylehidden1 = new StyleHidden() { Val = OnOffOnlyValues.Off }; - SemiHidden semihidden1 = new SemiHidden() { Val = OnOffOnlyValues.Off }; - StyleName styleName1 = new StyleName() { Val = stylename }; - NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" }; - UIPriority uipriority1 = new UIPriority() { Val = 1 }; - UnhideWhenUsed unhidewhenused1 = new UnhideWhenUsed() { Val = OnOffOnlyValues.On }; - if (aliases != "") - style.Append(aliases1); - style.Append(autoredefine1); - style.Append(basedon1); - style.Append(linkedStyle1); - style.Append(locked1); - style.Append(primarystyle1); - style.Append(stylehidden1); - style.Append(semihidden1); - style.Append(styleName1); - style.Append(nextParagraphStyle1); - style.Append(uipriority1); - style.Append(unhidewhenused1); - - // Create the StyleRunProperties object and specify some of the run properties. - StyleRunProperties styleRunProperties1 = new StyleRunProperties(); - Bold bold1 = new Bold(); - Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 }; - RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" }; - Italic italic1 = new Italic(); - // Specify a 12 point size. - FontSize fontSize1 = new FontSize() { Val = "24" }; - styleRunProperties1.Append(bold1); - styleRunProperties1.Append(color1); - styleRunProperties1.Append(font1); - styleRunProperties1.Append(fontSize1); - styleRunProperties1.Append(italic1); - - // Add the run properties to the style. - style.Append(styleRunProperties1); - - // Add the style to the styles part. - styles.Append(style); - } + styleDefinitionsPart.Styles = new Styles(); + styles = styleDefinitionsPart.Styles; + + styleDefinitionsPart.Styles.Save(); } + // + + // + // Create a new paragraph style element and specify some of the attributes. + Style style = new Style() + { + Type = StyleValues.Paragraph, + StyleId = styleid, + CustomStyle = true, + Default = false + }; + // + + // + // Create and add the child elements (properties of the style). + Aliases aliases1 = new Aliases() { Val = aliases }; + AutoRedefine autoredefine1 = new AutoRedefine() { Val = OnOffOnlyValues.Off }; + BasedOn basedon1 = new BasedOn() { Val = "Normal" }; + LinkedStyle linkedStyle1 = new LinkedStyle() { Val = "OverdueAmountChar" }; + Locked locked1 = new Locked() { Val = OnOffOnlyValues.Off }; + PrimaryStyle primarystyle1 = new PrimaryStyle() { Val = OnOffOnlyValues.On }; + StyleHidden stylehidden1 = new StyleHidden() { Val = OnOffOnlyValues.Off }; + SemiHidden semihidden1 = new SemiHidden() { Val = OnOffOnlyValues.Off }; + StyleName styleName1 = new StyleName() { Val = stylename }; + NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "Normal" }; + UIPriority uipriority1 = new UIPriority() { Val = 1 }; + UnhideWhenUsed unhidewhenused1 = new UnhideWhenUsed() { Val = OnOffOnlyValues.On }; + + if (string.IsNullOrWhiteSpace(aliases)) + { + style.Append(aliases1); + } + + style.Append(autoredefine1); + style.Append(basedon1); + style.Append(linkedStyle1); + style.Append(locked1); + style.Append(primarystyle1); + style.Append(stylehidden1); + style.Append(semihidden1); + style.Append(styleName1); + style.Append(nextParagraphStyle1); + style.Append(uipriority1); + style.Append(unhidewhenused1); + // + + // + // Create the StyleRunProperties object and specify some of the run properties. + StyleRunProperties styleRunProperties1 = new StyleRunProperties(); + Bold bold1 = new Bold(); + Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 }; + RunFonts font1 = new RunFonts() { Ascii = "Lucida Console" }; + Italic italic1 = new Italic(); + + // Specify a 12 point size. + FontSize fontSize1 = new FontSize() { Val = "24" }; + styleRunProperties1.Append(bold1); + styleRunProperties1.Append(color1); + styleRunProperties1.Append(font1); + styleRunProperties1.Append(fontSize1); + styleRunProperties1.Append(italic1); + + // Add the run properties to the style. + style.Append(styleRunProperties1); + + // Add the style to the styles part. + styles.Append(style); + // } // Add a StylesDefinitionsPart to the document. Returns a reference to it. @@ -89,4 +106,65 @@ static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument? doc) Styles root = new Styles(); root.Save(part); return part; -} \ No newline at end of file +} + +// +string strDoc = args[0]; + +using (WordprocessingDocument doc = WordprocessingDocument.Open(strDoc, true)) +{ + if (doc is null) + { + throw new ArgumentNullException("document could not be opened"); + } + + MainDocumentPart mainDocumentPart = doc.MainDocumentPart ?? doc.AddMainDocumentPart(); + + // Get the Styles part for this document. + StyleDefinitionsPart? part = mainDocumentPart.StyleDefinitionsPart; + + // If the Styles part does not exist, add it and then add the style. + if (part is null) + { + part = AddStylesPartToPackage(doc); + } + + // Set up a variable to hold the style ID. + string parastyleid = "OverdueAmountPara"; + + // Create and add a paragraph style to the specified styles part + // with the specified style ID, style name and aliases. + CreateAndAddParagraphStyle(part, parastyleid, "Overdue Amount Para", "Late Due, Late Amount"); + + // Add a paragraph with a run and some text. + Paragraph p = + new Paragraph( + new Run( + new Text("This is some text in a run in a paragraph."))); + + // Add the paragraph as a child element of the w:body element. + mainDocumentPart.Document ??= new Document(); + mainDocumentPart.Document.Body ??= new Body(); + + mainDocumentPart.Document.Body.AppendChild(p); + + // + // If the paragraph has no ParagraphProperties object, create one. + if (p.Elements().Count() == 0) + { + p.PrependChild(new ParagraphProperties()); + } + + // Get a reference to the ParagraphProperties object. + p.ParagraphProperties ??= new ParagraphProperties(); + ParagraphProperties pPr = p.ParagraphProperties; + + // If a ParagraphStyleId object doesn't exist, create one. + pPr.ParagraphStyleId ??= new ParagraphStyleId(); + + // Set the style of the paragraph. + pPr.ParagraphStyleId.Val = parastyleid; + // +} +// +// diff --git a/samples/word/create_and_add_a_paragraph_style/vb/Program.vb b/samples/word/create_and_add_a_paragraph_style/vb/Program.vb index 5c0ba268..dc0cb1f8 100644 --- a/samples/word/create_and_add_a_paragraph_style/vb/Program.vb +++ b/samples/word/create_and_add_a_paragraph_style/vb/Program.vb @@ -1,30 +1,86 @@ +' Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing Module Program Sub Main(args As String()) + ' + Dim filePath As String = args(0) + + Using wordprocessingDocument As WordprocessingDocument = WordprocessingDocument.Open(args(0), True) + + ' Get the Styles part for this document. + Dim part As StyleDefinitionsPart = wordprocessingDocument.MainDocumentPart.StyleDefinitionsPart + + ' If the Styles part does not exist, add it. + If part Is Nothing Then + part = AddStylesPartToPackage(wordprocessingDocument) + End If + + ' Set up a variable to hold the style ID. + Dim parastyleid As String = "OverdueAmountPara" + + ' Create and add a paragraph style to the specified styles part + ' with the specified style ID, style name and aliases. + CreateAndAddParagraphStyle(part, parastyleid, "Overdue Amount Para", "Late Due, Late Amount") + + ' Add a paragraph with a run and some text. + Dim p As New Paragraph(New Run(New Text("This is some text in a run in a paragraph."))) + + ' Add the paragraph as a child element of the w:body element. + wordprocessingDocument.MainDocumentPart.Document.Body.AppendChild(p) + + ' + ' If the paragraph has no ParagraphProperties object, create one. + If p.Elements(Of ParagraphProperties)().Count() = 0 Then + p.PrependChild(Of ParagraphProperties)(New ParagraphProperties()) + End If + + ' Get a reference to the ParagraphProperties object. + Dim pPr As ParagraphProperties = p.ParagraphProperties + + ' If a ParagraphStyleId object doesn't exist, create one. + If pPr.ParagraphStyleId Is Nothing Then + pPr.ParagraphStyleId = New ParagraphStyleId() + End If + + ' Set the style of the paragraph. + pPr.ParagraphStyleId.Val = parastyleid + ' + End Using + ' End Sub ' Create a new paragraph style with the specified style ID, primary style name, and aliases and ' add it to the specified style definitions part. - Public Sub CreateAndAddParagraphStyle(ByVal styleDefinitionsPart As StyleDefinitionsPart, - ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") + ' + Public Sub CreateAndAddParagraphStyle(ByVal styleDefinitionsPart As StyleDefinitionsPart, ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") + ' + + ' ' Access the root element of the styles part. Dim styles As Styles = styleDefinitionsPart.Styles + If styles Is Nothing Then styleDefinitionsPart.Styles = New Styles() styleDefinitionsPart.Styles.Save() + + styles = styleDefinitionsPart.Styles End If + ' + ' ' Create a new paragraph style element and specify some of the attributes. Dim style As New Style() With { .Type = StyleValues.Paragraph, .StyleId = styleid, .CustomStyle = True, .[Default] = False} + ' + ' ' Create and add the child elements (properties of the style) Dim aliases1 As New Aliases() With {.Val = aliases} Dim autoredefine1 As New AutoRedefine() With {.Val = OnOffOnlyValues.Off} @@ -40,9 +96,11 @@ Module Program Dim uipriority1 As New UIPriority() With {.Val = 1} Dim unhidewhenused1 As New UnhideWhenUsed() With { .Val = OnOffOnlyValues.[On]} - If aliases <> "" Then + + If String.IsNullOrWhiteSpace(aliases) Then style.Append(aliases1) End If + style.Append(autoredefine1) style.Append(basedon1) style.Append(linkedStyle1) @@ -54,6 +112,9 @@ Module Program style.Append(nextParagraphStyle1) style.Append(uipriority1) style.Append(unhidewhenused1) + ' + + ' ' Create the StyleRunProperties object and specify some of the run properties. Dim styleRunProperties1 As New StyleRunProperties() @@ -77,6 +138,7 @@ Module Program ' Add the style to the styles part. styles.Append(style) + ' End Sub ' Add a StylesDefinitionsPart to the document. Returns a reference to it. @@ -88,4 +150,5 @@ Module Program root.Save(part) Return part End Function -End Module \ No newline at end of file +End Module +' From a887549382976c6f3668fbac06e73572480dc446 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 13 May 2024 11:44:56 -0700 Subject: [PATCH 11/53] closes #212 --- ...ter-style-to-a-word-processing-document.md | 336 +++--------------- .../cs/Program.cs | 70 +++- .../vb/Program.vb | 172 ++++++--- 3 files changed, 243 insertions(+), 335 deletions(-) diff --git a/docs/word/how-to-create-and-add-a-character-style-to-a-word-processing-document.md b/docs/word/how-to-create-and-add-a-character-style-to-a-word-processing-document.md index 71da7845..03412755 100644 --- a/docs/word/how-to-create-and-add-a-character-style-to-a-word-processing-document.md +++ b/docs/word/how-to-create-and-add-a-character-style-to-a-word-processing-document.md @@ -12,7 +12,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 05/13/2024 ms.localizationpriority: medium --- # Create and add a character style to a word processing document @@ -20,36 +20,29 @@ ms.localizationpriority: medium This topic shows how to use the classes in the Open XML SDK for Office to programmatically create and add a character style to a word processing document. It contains an example -**CreateAndAddCharacterStyle** method to illustrate this task, plus a +`CreateAndAddCharacterStyle` method to illustrate this task, plus a supplemental example method to add the styles part when it is necessary. ## CreateAndAddCharacterStyle Method -The **CreateAndAddCharacterStyle** sample method can be used to add a +The `CreateAndAddCharacterStyle` sample method can be used to add a style to a word processing document. You must first obtain a reference to the style definitions part in the document to which you want to add -the style. See the Calling the Sample Method section for an example that +the style. See the [Calling the Sample Method](#calling-the-sample-method) section for an example that shows how to do this. -The method accepts four parameters that indicate: a reference to the -style definitions part, the style id of the style (an internal -identifier), the name of the style (for external use in the user -interface), and optionally, any style aliases (alternate names for use -in the user interface). +The method accepts four parameters that indicate: the path to the file to edit, +the style id of the style (an internal identifier), the name of the style +(for external use in the user interface), and optionally, any style aliases +(alternate names for use in the user interface). ### [C#](#tab/cs-0) -```csharp - public static void CreateAndAddCharacterStyle(StyleDefinitionsPart styleDefinitionsPart, - string styleid, string stylename, string aliases="") -``` +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Sub CreateAndAddCharacterStyle(ByVal styleDefinitionsPart As StyleDefinitionsPart, - ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet1)] *** @@ -77,7 +70,7 @@ definition. ``` -The style element styleId attribute defines the main internal identifier +The style element `styleId` attribute defines the main internal identifier of the style, the style ID (OverdueAmountChar). The aliases element specifies two alternate style names, Late Due, and Late Amount, which are comma separated. Each name must be separated by one or more commas. @@ -86,138 +79,27 @@ one typically shown in an application's user interface. ## Calling the Sample Method -You can use the **CreateAndAddCharacterStyle** +You can use the `CreateAndAddCharacterStyle` example method to create and add a named style to a word processing document using the Open XML SDK. The following code example shows how to open and obtain a reference to a word processing document, retrieve a reference to the document's style definitions part, and then call the -**CreateAndAddCharacterStyle** method. +`CreateAndAddCharacterStyle` method. -To call the method, you pass a reference to the style definitions part +To call the method, you pass a reference to the file to edit as the first parameter, the style ID of the style as the second parameter, the name of the style as the third parameter, and optionally, any style aliases as the fourth parameter. For example, the following code example creates the "Overdue Amount Char" character style in a -sample file that is named CreateAndAddCharacterStyle.docx. It also +sample file that's name comes from the first argument to the method. It also creates three runs of text in a paragraph, and applies the style to the second run. ### [C#](#tab/cs-1) -```csharp - string strDoc = @"C:\Users\Public\Documents\CreateAndAddCharacterStyle.docx"; - - using (WordprocessingDocument doc = - WordprocessingDocument.Open(strDoc, true)) - { - // Get the Styles part for this document. - StyleDefinitionsPart part = - doc.MainDocumentPart.StyleDefinitionsPart; - - // If the Styles part does not exist, add it. - if (part == null) - { - part = AddStylesPartToPackage(doc); - } - - // Create and add the character style with the style id, style name, and - // aliases specified. - CreateAndAddCharacterStyle(part, - "OverdueAmountChar", - "Overdue Amount Char", - "Late Due, Late Amount"); - - // Add a paragraph with a run with some text. - Paragraph p = - new Paragraph( - new Run( - new Text("this is some text "){Space = SpaceProcessingModeValues.Preserve})); - - // Add another run with some text. - p.AppendChild(new Run(new Text("in a run "){Space = SpaceProcessingModeValues.Preserve})); - - // Add another run with some text. - p.AppendChild(new Run(new Text("in a paragraph."){Space = SpaceProcessingModeValues.Preserve})); - - // Add the paragraph as a child element of the w:body. - doc.MainDocumentPart.Document.Body.AppendChild(p); - - // Get a reference to the second run (indexed starting with 0). - Run r = p.Descendants().ElementAtOrDefault(1); - - // If the Run has no RunProperties object, create one. - if (r.Elements().Count() == 0) - { - r.PrependChild(new RunProperties()); - } - - // Get a reference to the RunProperties. - RunProperties rPr = r.RunProperties; - - // Set the character style of the run. - if (rPr.RunStyle == null) - rPr.RunStyle = new RunStyle(); - rPr.RunStyle.Val = "OverdueAmountChar"; -``` +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim strDoc As String = "C:\Users\Public\Documents\CreateAndAddCharacterStyle.docx" - - Using doc As WordprocessingDocument = - WordprocessingDocument.Open(strDoc, True) - - ' Get the Styles part for this document. - Dim part As StyleDefinitionsPart = - doc.MainDocumentPart.StyleDefinitionsPart - - ' If the Styles part does not exist, add it. - If part Is Nothing Then - part = AddStylesPartToPackage(doc) - End If - - ' Create and add the character style with the style id, style name, and - ' aliases specified. - CreateAndAddCharacterStyle(part, - "OverdueAmountChar", - "Overdue Amount Char", - "Late Due, Late Amount") - - ' Add a paragraph with a run with some text. - Dim p As New Paragraph( - New Run( - New Text("This is some text ") With { _ - .Space = SpaceProcessingModeValues.Preserve})) - - ' Add another run with some text. - p.AppendChild(Of Run)(New Run(New Text("in a run ") With { _ - .Space = SpaceProcessingModeValues.Preserve})) - - ' Add another run with some text. - p.AppendChild(Of Run)(New Run(New Text("in a paragraph.") With { _ - .Space = SpaceProcessingModeValues.Preserve})) - - ' Add the paragraph as a child element of the w:body. - doc.MainDocumentPart.Document.Body.AppendChild(p) - - ' Get a reference to the second run (indexed starting with 0). - Dim r As Run = p.Descendants(Of Run)().ElementAtOrDefault(1) - - ' If the Run has no RunProperties object, create one. - If r.Elements(Of RunProperties)().Count() = 0 Then - r.PrependChild(Of RunProperties)(New RunProperties()) - End If - - ' Get a reference to the RunProperties. - Dim rPr As RunProperties = r.RunProperties - - ' Set the character style of the run. - If rPr.RunStyle Is Nothing Then - rPr.RunStyle = New RunStyle() - End If - rPr.RunStyle.Val = "OverdueAmountChar" - - End Using -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet2)] *** @@ -272,17 +154,17 @@ runs of text within a document's contents. This definition implies that the style can only define character properties (properties which apply to text within a paragraph) because it cannot be applied to paragraphs. Character styles can only be referenced by runs within a document, and -they shall be referenced by the rStyle element within a run's run -propertieselement. +they shall be referenced by the `rStyle` element within a run's run +properties element. A character style has two defining style type-specific characteristics: - The type attribute on the style has a value of character, which indicates that the following style definition is a character style. -- The style specifies only character-level properties using the rPr element. In this case, the run properties are the set of properties applied to each run which is of this style. +- The style specifies only character-level properties using the `rPr` element. In this case, the run properties are the set of properties applied to each run which is of this style. -The character style is then applied to runs by referencing the styleId -attribute value for this style in the run properties' rStyle element. +The character style is then applied to runs by referencing the `styleId` +attribute value for this style in the run properties' `rStyle` element. The following image shows some text that has had a character style applied. A character style can only be applied to a sub-paragraph level @@ -294,59 +176,29 @@ Figure 1. Text with a character style applied ## How the Code Works -The **CreateAndAddCharacterStyle** method -begins by retrieving a reference to the styles element in the styles +The `CreateAndAddCharacterStyle` method +begins by opening the specified file and retrieving a reference to the styles element in the styles part. The styles element is the root element of the part and contains all of the individual style elements. If the reference is null, the styles element is created and saved to the part. ### [C#](#tab/cs-2) -```csharp - // Get access to the root element of the styles part. - Styles styles = styleDefinitionsPart.Styles; - if (styles == null) - { - styleDefinitionsPart.Styles = new Styles(); - styleDefinitionsPart.Styles.Save(); - } -``` +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - ' Get access to the root element of the styles part. - Dim styles As Styles = styleDefinitionsPart.Styles - If styles Is Nothing Then - styleDefinitionsPart.Styles = New Styles() - styleDefinitionsPart.Styles.Save() - End If -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet3)] *** ## Creating the Style -To create the style, the code instantiates the [Style](/dotnet/api/documentformat.openxml.wordprocessing.style) class and sets certain properties, -such as the [Type](/dotnet/api/documentformat.openxml.wordprocessing.style.type) of style (paragraph), the [StyleId](/dotnet/api/documentformat.openxml.wordprocessing.style.styleid), and whether the style is a [CustomStyle](/dotnet/api/documentformat.openxml.wordprocessing.style.customstyle). +To create the style, the code instantiates the class and sets certain properties, +such as the of style (paragraph), the , and whether the style is a . ### [C#](#tab/cs-3) -```csharp - // Create a new character style and specify some of the attributes. - Style style = new Style() - { - Type = StyleValues.Character, - StyleId = styleid, - CustomStyle = true - }; -``` - +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' Create a new character style and specify some of the attributes. - Dim style As New Style() With { _ - .Type = StyleValues.Character, _ - .StyleId = styleid, _ - .CustomStyle = True} -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet4)] *** @@ -359,90 +211,29 @@ The code results in the following XML. The code next creates the child elements of the style, which define the properties of the style. To create an element, you instantiate its -corresponding class, and then call the [Append(\[\])](/dotnet/api/documentformat.openxml.openxmlelement.append) method to add the child element +corresponding class, and then call the method to add the child element to the style. For more information about these properties, see section 17.7 of the [!include[ISO/IEC 29500 URL](../includes/iso-iec-29500-link.md)] specification. ### [C#](#tab/cs-4) -```csharp - // Create and add the child elements (properties of the style). - Aliases aliases1 = new Aliases() { Val = aliases }; - StyleName styleName1 = new StyleName() { Val = stylename }; - LinkedStyle linkedStyle1 = new LinkedStyle() { Val = "OverdueAmountPara" }; - if (aliases != "") - style.Append(aliases1); - style.Append(styleName1); - style.Append(linkedStyle1); -``` - +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - ' Create and add the child elements (properties of the style). - Dim aliases1 As New Aliases() With {.Val = aliases} - Dim styleName1 As New StyleName() With {.Val = stylename} - Dim linkedStyle1 As New LinkedStyle() With {.Val = "OverdueAmountPara"} - If aliases <> "" Then - style.Append(aliases1) - End If - style.Append(styleName1) - style.Append(linkedStyle1) -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet5)] *** -Next, the code instantiates a [StyleRunProperties](/dotnet/api/documentformat.openxml.wordprocessing.stylerunproperties) object to create a **rPr** (Run Properties) element. You specify the +Next, the code instantiates a +object to create a `rPr` (Run Properties) element. You specify the character properties that apply to the style, such as font and color, in -this element. The properties are then appended as children of the **rPr** element. +this element. The properties are then appended as children of the `rPr` element. -When the run properties are created, the code appends the **rPr** element to the style, and the style element +When the run properties are created, the code appends the `rPr` element to the style, and the style element to the styles root element in the styles part. ### [C#](#tab/cs-5) -```csharp - // Create the StyleRunProperties object and specify some of the run properties. - StyleRunProperties styleRunProperties1 = new StyleRunProperties(); - Bold bold1 = new Bold(); - Color color1 = new Color() { ThemeColor = ThemeColorValues.Accent2 }; - RunFonts font1 = new RunFonts() { Ascii = "Tahoma" }; - Italic italic1 = new Italic(); - // Specify a 24 point size. - FontSize fontSize1 = new FontSize() { Val = "48" }; - styleRunProperties1.Append(font1); - styleRunProperties1.Append(fontSize1); - styleRunProperties1.Append(color1); - styleRunProperties1.Append(bold1); - styleRunProperties1.Append(italic1); - - // Add the run properties to the style. - style.Append(styleRunProperties1); - - // Add the style to the styles part. - styles.Append(style); -``` - +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - ' Create the StyleRunProperties object and specify some of the run properties. - Dim styleRunProperties1 As New StyleRunProperties() - Dim bold1 As New Bold() - Dim color1 As New Color() With { _ - .ThemeColor = ThemeColorValues.Accent2} - Dim font1 As New RunFonts() With {.Ascii = "Tahoma"} - Dim italic1 As New Italic() - ' Specify a 24 point size. - Dim fontSize1 As New FontSize() With {.Val = "48"} - styleRunProperties1.Append(font1) - styleRunProperties1.Append(fontSize1) - styleRunProperties1.Append(color1) - styleRunProperties1.Append(bold1) - styleRunProperties1.Append(italic1) - - ' Add the run properties to the style. - style.Append(styleRunProperties1) - - ' Add the style to the styles part. - styles.Append(style) -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet6)] *** @@ -466,60 +257,33 @@ The following XML shows the final style generated by the code shown here. ## Applying the Character Style Once you have the style created, you can apply it to a run by -referencing the styleId attribute value for this style in the run -properties' **rStyle** element. The following +referencing the `styleId` attribute value for this style in the run +properties' `rStyle` element. The following code example shows how to apply a style to a run referenced by the variable r. The style ID of the style to apply, OverdueAmountChar in -this example, is stored in the RunStyle property of the **rPr** object. This property represents the run -properties' **rStyle** element. +this example, is stored in the RunStyle property of the `rPr` object. This property represents the run +properties' `rStyle` element. ### [C#](#tab/cs-6) -```csharp - // If the Run has no RunProperties object, create one. - if (r.Elements().Count() == 0) - { - r.PrependChild(new RunProperties()); - } - - // Get a reference to the RunProperties. - RunProperties rPr = r.RunProperties; - - // Set the character style of the run. - if (rPr.RunStyle == null) - rPr.RunStyle = new RunStyle(); - rPr.RunStyle.Val = "OverdueAmountChar"; -``` - +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - ' If the Run has no RunProperties object, create one. - If r.Elements(Of RunProperties)().Count() = 0 Then - r.PrependChild(Of RunProperties)(New RunProperties()) - End If - - ' Get a reference to the RunProperties. - Dim rPr As RunProperties = r.RunProperties - - ' Set the character style of the run. - If rPr.RunStyle Is Nothing Then - rPr.RunStyle = New RunStyle() - End If - rPr.RunStyle.Val = "OverdueAmountChar" -``` +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet7)] *** ## Sample Code -The following is the complete **CreateAndAddCharacterStyle** code sample in both C\# and Visual Basic. +The following is the complete `CreateAndAddCharacterStyle` code sample in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs)] +[!code-csharp[](../../samples/word/create_and_add_a_character_style/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb)] +[!code-vb[](../../samples/word/create_and_add_a_character_style/vb/Program.vb#snippet0)] +*** ## See also [How to: Apply a style to a paragraph in a word processing document](how-to-apply-a-style-to-a-paragraph-in-a-word-processing-document.md) + [Open XML SDK class library reference](/office/open-xml/open-xml-sdk) diff --git a/samples/word/create_and_add_a_character_style/cs/Program.cs b/samples/word/create_and_add_a_character_style/cs/Program.cs index 1a86e82b..c7a9aaf4 100644 --- a/samples/word/create_and_add_a_character_style/cs/Program.cs +++ b/samples/word/create_and_add_a_character_style/cs/Program.cs @@ -1,20 +1,28 @@ +using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; +using System.Linq; CreateAndAddCharacterStyle(args[0], args[1], args[2], args[3]); +// // Create a new character style with the specified style id, style name and aliases and -// add it to the specified style definitions part. +// add it to the specified file. +// static void CreateAndAddCharacterStyle(string filePath, string styleid, string stylename, string aliases = "") +// { + // using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filePath, true)) { // Get access to the root element of the styles part. Styles? styles = wordprocessingDocument?.MainDocumentPart?.StyleDefinitionsPart?.Styles ?? AddStylesPartToPackage(wordprocessingDocument).Styles; + // if (styles is not null) { + // // Create a new character style and specify some of the attributes. Style style = new Style() { @@ -22,16 +30,24 @@ static void CreateAndAddCharacterStyle(string filePath, string styleid, string s StyleId = styleid, CustomStyle = true }; + // + // // Create and add the child elements (properties of the style). Aliases aliases1 = new Aliases() { Val = aliases }; StyleName styleName1 = new StyleName() { Val = stylename }; LinkedStyle linkedStyle1 = new LinkedStyle() { Val = "OverdueAmountPara" }; - if (aliases != "") + + if (!String.IsNullOrEmpty(aliases)) + { style.Append(aliases1); + } + style.Append(styleName1); style.Append(linkedStyle1); + // + // // Create the StyleRunProperties object and specify some of the run properties. StyleRunProperties styleRunProperties1 = new StyleRunProperties(); Bold bold1 = new Bold(); @@ -51,6 +67,7 @@ static void CreateAndAddCharacterStyle(string filePath, string styleid, string s // Add the style to the styles part. styles.Append(style); + // } } } @@ -69,4 +86,51 @@ static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument? doc) Styles root = new Styles(); root.Save(part); return part; -} \ No newline at end of file +} +// + +// +static void AddStylesToPackage(string filePath) +{ + // Create and add the character style with the style id, style name, and + // aliases specified. + CreateAndAddCharacterStyle( + filePath, + "OverdueAmountChar", + "Overdue Amount Char", + "Late Due, Late Amount"); + + using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true)) + { + + // Add a paragraph with a run with some text. + Paragraph p = new Paragraph( + new Run( + new Text("this is some text ") { Space = SpaceProcessingModeValues.Preserve })); + + // Add another run with some text. + p.AppendChild(new Run(new Text("in a run ") { Space = SpaceProcessingModeValues.Preserve })); + + // Add another run with some text. + p.AppendChild(new Run(new Text("in a paragraph.") { Space = SpaceProcessingModeValues.Preserve })); + + // Add the paragraph as a child element of the w:body. + doc?.MainDocumentPart?.Document?.Body?.AppendChild(p); + + // Get a reference to the second run (indexed starting with 0). + Run r = p.Descendants().ElementAtOrDefault(1)!; + + // + // If the Run has no RunProperties object, create one and get a reference to it. + RunProperties rPr = r.RunProperties ?? r.PrependChild(new RunProperties()); + + // Set the character style of the run. + if (rPr.RunStyle is null) + { + rPr.RunStyle = new RunStyle(); + rPr.RunStyle.Val = "OverdueAmountChar"; + } + // + } +} +// \ No newline at end of file diff --git a/samples/word/create_and_add_a_character_style/vb/Program.vb b/samples/word/create_and_add_a_character_style/vb/Program.vb index 41cc90cc..c1648184 100644 --- a/samples/word/create_and_add_a_character_style/vb/Program.vb +++ b/samples/word/create_and_add_a_character_style/vb/Program.vb @@ -1,3 +1,4 @@ +Imports DocumentFormat.OpenXml Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing Imports Bold = DocumentFormat.OpenXml.Wordprocessing.Bold @@ -7,56 +8,83 @@ Imports Italic = DocumentFormat.OpenXml.Wordprocessing.Italic Module Program Sub Main(args As String()) - End Sub + Dim filePath As String = args(0) + Dim styleid As String = args(1) + Dim stylename As String = args(2) + Dim aliases As String = If(args(3) Is Nothing, "", args(3)) + CreateAndAddCharacterStyle(filePath, styleid, stylename, aliases) + End Sub + ' ' Create a new character style with the specified style id, style name and aliases and add ' it to the specified style definitions part. - Public Sub CreateAndAddCharacterStyle(ByVal styleDefinitionsPart As StyleDefinitionsPart, - ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") - ' Get access to the root element of the styles part. - Dim styles As Styles = styleDefinitionsPart.Styles - If styles Is Nothing Then - styleDefinitionsPart.Styles = New Styles() - styleDefinitionsPart.Styles.Save() - End If - - ' Create a new character style and specify some of the attributes. - Dim style As New Style() With { - .Type = StyleValues.Character, - .StyleId = styleid, - .CustomStyle = True} - - ' Create and add the child elements (properties of the style). - Dim aliases1 As New Aliases() With {.Val = aliases} - Dim styleName1 As New StyleName() With {.Val = stylename} - Dim linkedStyle1 As New LinkedStyle() With {.Val = "OverdueAmountPara"} - If aliases <> "" Then - style.Append(aliases1) - End If - style.Append(styleName1) - style.Append(linkedStyle1) - - ' Create the StyleRunProperties object and specify some of the run properties. - Dim styleRunProperties1 As New StyleRunProperties() - Dim bold1 As New Bold() - Dim color1 As New Color() With { - .ThemeColor = ThemeColorValues.Accent2} - Dim font1 As New RunFonts() With {.Ascii = "Tahoma"} - Dim italic1 As New Italic() - ' Specify a 24 point size. - Dim fontSize1 As New FontSize() With {.Val = "48"} - styleRunProperties1.Append(font1) - styleRunProperties1.Append(fontSize1) - styleRunProperties1.Append(color1) - styleRunProperties1.Append(bold1) - styleRunProperties1.Append(italic1) - - ' Add the run properties to the style. - style.Append(styleRunProperties1) - - ' Add the style to the styles part. - styles.Append(style) + ' + Public Sub CreateAndAddCharacterStyle(ByVal filePath As String, ByVal styleid As String, ByVal stylename As String, Optional ByVal aliases As String = "") + ' + + ' Open the document for editing. + ' + Using doc As WordprocessingDocument = WordprocessingDocument.Open(filePath, True) + Dim styleDefinitionsPart As StyleDefinitionsPart = doc.MainDocumentPart.StyleDefinitionsPart + + If styleDefinitionsPart Is Nothing Then + styleDefinitionsPart = AddStylesPartToPackage(doc) + End If + ' + + ' Get access to the root element of the styles part. + Dim styles As Styles = styleDefinitionsPart.Styles + If styles Is Nothing Then + styleDefinitionsPart.Styles = New Styles() + styleDefinitionsPart.Styles.Save() + End If + + ' + ' Create a new character style and specify some of the attributes. + Dim style As New Style() With { + .Type = StyleValues.Character, + .StyleId = styleid, + .CustomStyle = True} + ' + + ' + ' Create and add the child elements (properties of the style). + Dim aliases1 As New Aliases() With {.Val = aliases} + Dim styleName1 As New StyleName() With {.Val = stylename} + Dim linkedStyle1 As New LinkedStyle() With {.Val = "OverdueAmountPara"} + + If aliases <> "" Then + style.Append(aliases1) + End If + + style.Append(styleName1) + style.Append(linkedStyle1) + ' + + ' + ' Create the StyleRunProperties object and specify some of the run properties. + Dim styleRunProperties1 As New StyleRunProperties() + Dim bold1 As New Bold() + Dim color1 As New Color() With { + .ThemeColor = ThemeColorValues.Accent2} + Dim font1 As New RunFonts() With {.Ascii = "Tahoma"} + Dim italic1 As New Italic() + ' Specify a 24 point size. + Dim fontSize1 As New FontSize() With {.Val = "48"} + styleRunProperties1.Append(font1) + styleRunProperties1.Append(fontSize1) + styleRunProperties1.Append(color1) + styleRunProperties1.Append(bold1) + styleRunProperties1.Append(italic1) + + ' Add the run properties to the style. + style.Append(styleRunProperties1) + + ' Add the style to the styles part. + styles.Append(style) + ' + End Using End Sub ' Add a StylesDefinitionsPart to the document. Returns a reference to it. @@ -68,4 +96,56 @@ Module Program root.Save(part) Return part End Function + ' + + ' + Public Sub AddStylesToPackage(ByVal filePath As String) + ' Create and add the character style with the style id, style name, and + ' aliases specified. + CreateAndAddCharacterStyle(filePath, + "OverdueAmountChar", + "Overdue Amount Char", + "Late Due, Late Amount") + + Using doc As WordprocessingDocument = WordprocessingDocument.Open(filePath, True) + + + ' Add a paragraph with a run with some text. + Dim p As New Paragraph( + New Run( + New Text("This is some text ") With { + .Space = SpaceProcessingModeValues.Preserve})) + + ' Add another run with some text. + p.AppendChild(Of Run)(New Run(New Text("in a run ") With { + .Space = SpaceProcessingModeValues.Preserve})) + + ' Add another run with some text. + p.AppendChild(Of Run)(New Run(New Text("in a paragraph.") With { + .Space = SpaceProcessingModeValues.Preserve})) + + ' Add the paragraph as a child element of the w:body. + doc.MainDocumentPart.Document.Body.AppendChild(p) + + ' Get a reference to the second run (indexed starting with 0). + Dim r As Run = p.Descendants(Of Run)().ElementAtOrDefault(1) + + ' + ' If the Run has no RunProperties object, create one. + If r.Elements(Of RunProperties)().Count() = 0 Then + r.PrependChild(Of RunProperties)(New RunProperties()) + End If + + ' Get a reference to the RunProperties. + Dim rPr As RunProperties = r.RunProperties + + ' Set the character style of the run. + If rPr.RunStyle Is Nothing Then + rPr.RunStyle = New RunStyle() + End If + rPr.RunStyle.Val = "OverdueAmountChar" + ' + End Using + End Sub + ' End Module \ No newline at end of file From bb1f6346d22434aa3169f4cfb9ea285f1ee03131 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 13 May 2024 13:58:37 -0700 Subject: [PATCH 12/53] closes #211 --- ...ssing-document-by-providing-a-file-name.md | 59 ++++++++----------- .../cs/Program.cs | 6 ++ .../vb/Program.vb | 10 +++- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md b/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md index b4af6ddd..6a572ae2 100644 --- a/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md +++ b/docs/word/how-to-create-a-word-processing-document-by-providing-a-file-name.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 05/13/2024 ms.localizationpriority: high --- # Create a word processing document by providing a file name @@ -23,6 +23,7 @@ Office to programmatically create a word processing document. -------------------------------------------------------------------------------- ## Creating a WordprocessingDocument Object + In the Open XML SDK, the class represents a Word document package. To create a Word document, you create an instance of the class and @@ -31,41 +32,30 @@ document part that serves as a container for the main text of the document. The text is represented in the package as XML using WordprocessingML markup. -To create the class instance you call the [Create(String, WordprocessingDocumentType)](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.create) -method. Several [Create()](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.create) methods are provided, each with a -different signature. The sample code in this topic uses the **Create** method with a signature that requires two +To create the class instance you call the +method. Several methods are provided, each with a +different signature. The sample code in this topic uses the `Create` method with a signature that requires two parameters. The first parameter takes a full path string that represents the document that you want to create. The second parameter is a member of the enumeration. This parameter represents the type of document. For example, there is a -different member of the **WordProcessingDocumentType** enumeration for each +different member of the `WordProcessingDocumentType` enumeration for each of document, template, and the macro enabled variety of document and template. > [!NOTE] -> Carefully select the appropriate **WordProcessingDocumentType** and verify that the persisted file has the correct, matching file extension. If the **>WordProcessingDocumentType** does not match the file extension, an error occurs when you open the file in Microsoft Word. +> Carefully select the appropriate `WordProcessingDocumentType` and verify that the persisted file has the correct, matching file extension. If the `WordProcessingDocumentType` does not match the file extension, an error occurs when you open the file in Microsoft Word. -The code that calls the **Create** method is -part of a **using** statement followed by a +The code that calls the `Create` method is +part of a `using` statement followed by a bracketed block, as shown in the following code example. ### [C#](#tab/cs-0) -```csharp - using (WordprocessingDocument wordDocument = - WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document)) - { - // Insert other code here. - } -``` - +[!code-csharp[](../../samples/word/create_by_providing_a_file_name/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Using wordDocument As WordprocessingDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document) - ' Insert other code here. - End Using -``` +[!code-vb[](../../samples/word/create_by_providing_a_file_name/vb/Program.vb#snippet1)] *** [!include[Using Statement](../includes/using-statement.md)] @@ -81,14 +71,15 @@ you can set about adding the document structure and text. -------------------------------------------------------------------------------- ## Generating the WordprocessingML Markup + To create the basic document structure using the Open XML SDK, you -instantiate the **Document** class, assign it -to the **Document** property of the main -document part, and then add instances of the **Body**, **Paragraph**, -**Run** and **Text** +instantiate the `Document` class, assign it +to the `Document` property of the main +document part, and then add instances of the `Body`, `Paragraph`, +`Run` and `Text` classes. This is shown in the sample code listing, and does the work of generating the required WordprocessingML markup. While the code in the -sample listing calls the **AppendChild** method +sample listing calls the `AppendChild` method of each class, you can sometimes make code shorter and easier to read by using the technique shown in the following code example. @@ -110,20 +101,15 @@ using the technique shown in the following code example. -------------------------------------------------------------------------------- ## Sample Code -The **CreateWordprocessingDocument** method can +The `CreateWordprocessingDocument` method can be used to create a basic Word document. You call it by passing a full path as the only parameter. The following code example creates the Invoice.docx file in the Public Documents folder. ### [C#](#tab/cs-2) -```csharp - CreateWordprocessingDocument(@"c:\Users\Public\Documents\Invoice.docx"); -``` - +[!code-csharp[](../../samples/word/create_by_providing_a_file_name/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-2) -```vb - CreateWordprocessingDocument("c:\Users\Public\Documents\Invoice.docx") -``` +[!code-vb[](../../samples/word/create_by_providing_a_file_name/vb/Program.vb#snippet2)] *** @@ -134,10 +120,11 @@ parameter in the call to the **Create** method. Following is the complete code example in both C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/create_by_providing_a_file_name/cs/Program.cs)] +[!code-csharp[](../../samples/word/create_by_providing_a_file_name/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/create_by_providing_a_file_name/vb/Program.vb)] +[!code-vb[](../../samples/word/create_by_providing_a_file_name/vb/Program.vb#snippet0)] +*** -------------------------------------------------------------------------------- ## See also diff --git a/samples/word/create_by_providing_a_file_name/cs/Program.cs b/samples/word/create_by_providing_a_file_name/cs/Program.cs index d2417d83..c531ef35 100644 --- a/samples/word/create_by_providing_a_file_name/cs/Program.cs +++ b/samples/word/create_by_providing_a_file_name/cs/Program.cs @@ -3,13 +3,18 @@ using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; +// CreateWordprocessingDocument(args[0]); +// +// static void CreateWordprocessingDocument(string filepath) { // Create a document by supplying the filepath. + // using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document)) { + // // Add a main document part. MainDocumentPart mainPart = wordDocument.AddMainDocumentPart(); @@ -20,4 +25,5 @@ static void CreateWordprocessingDocument(string filepath) Run run = para.AppendChild(new Run()); run.AppendChild(new Text("Create text in body - CreateWordprocessingDocument")); } + // } diff --git a/samples/word/create_by_providing_a_file_name/vb/Program.vb b/samples/word/create_by_providing_a_file_name/vb/Program.vb index 5a7a6919..e2f92a8d 100644 --- a/samples/word/create_by_providing_a_file_name/vb/Program.vb +++ b/samples/word/create_by_providing_a_file_name/vb/Program.vb @@ -6,12 +6,17 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module MyModule Sub Main(args As String()) + ' + CreateWordprocessingDocument(args(0)) + ' End Sub + ' Public Sub CreateWordprocessingDocument(ByVal filepath As String) ' Create a document by supplying the filepath. - Using wordDocument As WordprocessingDocument = - WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document) + ' + Using wordDocument As WordprocessingDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document) + ' ' Add a main document part. Dim mainPart As MainDocumentPart = wordDocument.AddMainDocumentPart() @@ -24,4 +29,5 @@ Module MyModule run.AppendChild(New Text("Create text in body - CreateWordprocessingDocument")) End Using End Sub + ' End Module \ No newline at end of file From 1d5930b2774ce46994ecfe3165b8edb661d8f20e Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 13 May 2024 15:11:24 -0700 Subject: [PATCH 13/53] closes #210 --- ...t-from-the-docm-to-the-docx-file-format.md | 151 +++--------------- .../cs/Program.cs | 19 ++- .../vb/Program.vb | 18 ++- 3 files changed, 58 insertions(+), 130 deletions(-) diff --git a/docs/word/how-to-convert-a-word-processing-document-from-the-docm-to-the-docx-file-format.md b/docs/word/how-to-convert-a-word-processing-document-from-the-docm-to-the-docx-file-format.md index 645aa7ad..7e82f772 100644 --- a/docs/word/how-to-convert-a-word-processing-document-from-the-docm-to-the-docx-file-format.md +++ b/docs/word/how-to-convert-a-word-processing-document-from-the-docm-to-the-docx-file-format.md @@ -13,7 +13,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 05/13/2024 ms.localizationpriority: high --- @@ -22,27 +22,22 @@ ms.localizationpriority: high This topic shows how to use the classes in the Open XML SDK for Office to programmatically convert a Microsoft Word document that contains VBA code (and has a .docm extension) to a standard document (with a .docx extension). It contains an example -**ConvertDOCMtoDOCX** method to illustrate this task. +`ConvertDOCMtoDOCX` method to illustrate this task. ## ConvertDOCMtoDOCX Method -The **ConvertDOCMtoDOCX** sample method can be used to convert a Word document that contains VBA code (and has a .docm +The `ConvertDOCMtoDOCX` sample method can be used to convert a Word document that contains VBA code (and has a .docm extension) to a standard document (with a .docx extension). Use this method to remove the macros and the vbaProject part that contains them from a document stored in .docm file format. The method accepts a single parameter that indicates the file name of the file to convert. ### [C#](#tab/cs-0) -```csharp - public static void ConvertDOCMtoDOCX(string fileName) -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Sub ConvertDOCMtoDOCX(ByVal fileName As String) -``` +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet1)] *** @@ -54,16 +49,9 @@ To call the sample method, pass a string that contains the name of the file to convert. The following sample code shows an example. ### [C#](#tab/cs-1) -```csharp - string filename = @"C:\Users\Public\Documents\WithMacros.docm"; - ConvertDOCMtoDOCX(filename); -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Dim filename As String = "C:\Users\Public\Documents\WithMacros.docm" - ConvertDOCMtoDOCX(filename) -``` +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet2)] *** @@ -76,7 +64,7 @@ contain content equivalent to an external XML file, binary file, image file, and so on, depending on the type. The standard that defines how Open XML documents are stored in .zip files is called the Open Packaging Conventions. For more information about the Open Packaging Conventions, -see [ISO/IEC 29500-2](https://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=51459). +see [ISO/IEC 29500-2:2021](https://www.iso.org/standard/77818.html). When you create and save a VBA macro in a document, Word adds a new binary part named vbaProject that contains the internal representation @@ -88,6 +76,7 @@ vbaProject part is highlighted. Figure 1. The vbaProject part ![vbaProject part shown in the Document Explorer](../media/OpenXMLCon_HowToConvertDOCMtoDOCX_Fig1.gif) + The task of converting a macro enabled document to one that is not macro enabled therefore consists largely of removing the vbaProject part from the document package. @@ -99,87 +88,32 @@ the document contains a vbaProject part, and deleting the part. After the code deletes the part, it changes the document type internally and renames the document so that it uses the .docx extension. -The code starts by opening the document by using the **Open** method and indicating that the document should be open for read/write access (the final true parameter). The code then retrieves a reference to the Document part by using the **MainDocumentPart** property of the word processing document. +The code starts by opening the document by using the `Open` method and indicating that the document should be open for read/write access (the final true parameter). The code then retrieves a reference to the Document part by using the `MainDocumentPart` property of the word processing document. ### [C#](#tab/cs-2) -```csharp - using (WordprocessingDocument document = - WordprocessingDocument.Open(fileName, true)) - { - // Get access to the main document part. - var docPart = document.MainDocumentPart; - // Code removed here… - } -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - Using document As WordprocessingDocument = - WordprocessingDocument.Open(fileName, True) - - ' Access the main document part. - Dim docPart = document.MainDocumentPart - ' Code removed here… - End Using -``` -*** +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet3)] +`* -The sample code next verifies that the vbaProject part exists, deletes the part and saves the document. The code has no effect if the file to convert does not contain a vbaProject part. To find the part, the sample code retrieves the **VbaProjectPart** property of the document. It calls the **DeletePart** method to delete the part, and then calls the **Save** method of the document to save the changes. +The sample code next verifies that the vbaProject part exists, deletes the part and saves the document. The code has no effect if the file to convert does not contain a vbaProject part. To find the part, the sample code retrieves the `VbaProjectPart` property of the document. It calls the `DeletePart` method to delete the part, and then calls the `Save` method of the document to save the changes. ### [C#](#tab/cs-3) -```csharp - // Look for the vbaProject part. If it is there, delete it. - var vbaPart = docPart.VbaProjectPart; - if (vbaPart != null) - { - // Delete the vbaProject part and then save the document. - docPart.DeletePart(vbaPart); - docPart.Document.Save(); - // Code removed here. - } -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' Look for the vbaProject part. If it is there, delete it. - Dim vbaPart = docPart.VbaProjectPart - If vbaPart IsNot Nothing Then - - ' Delete the vbaProject part and then save the document. - docPart.DeletePart(vbaPart) - docPart.Document.Save() - ' Code removed here… - End If -``` +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet4)] *** -It is not enough to delete the part from the document. You must also convert the document type, internally. The Open XML SDK provides a way to perform this task: You can call the document **ChangeDocumentType** method and indicate the new document type (in this case, supply the *WordProcessingDocumentType.Document* enumerated value). +It is not enough to delete the part from the document. You must also convert the document type, internally. The Open XML SDK provides a way to perform this task: You can call the document `ChangeDocumentType` method and indicate the new document type (in this case, supply the enumerated value). -You must also rename the file. However, you cannot do that while the file is open. The using block closes the file at the end of the block. Therefore, you must have some way to indicate to the code after the block that you have modified the file: The **fileChanged** Boolean variable tracks this information for you. +You must also rename the file. However, you cannot do that while the file is open. The using block closes the file at the end of the block. Therefore, you must have some way to indicate to the code after the block that you have modified the file: The `fileChanged` Boolean variable tracks this information for you. ### [C#](#tab/cs-4) -```csharp - // Change the document type to - // not macro-enabled. - document.ChangeDocumentType( - WordprocessingDocumentType.Document); - - // Track that the document has been changed. - fileChanged = true; -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-4) -```vb - ' Change the document type to - ' not macro-enabled. - document.ChangeDocumentType( - WordprocessingDocumentType.Document) - - ' Track that the document has been changed. - fileChanged = True -``` +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet4)] *** @@ -189,56 +123,23 @@ output file exists and deletes it, and finally moves the file from the old file name to the new file name. ### [C#](#tab/cs-5) -```csharp - // If anything goes wrong in this file handling, - // the code will raise an exception back to the caller. - if (fileChanged) - { - // Create the new .docx filename. - var newFileName = Path.ChangeExtension(fileName, ".docx"); - - // If it already exists, it will be deleted! - if (File.Exists(newFileName)) - { - File.Delete(newFileName); - } - - // Rename the file. - File.Move(fileName, newFileName); - } -``` - +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - ' If anything goes wrong in this file handling, - ' the code will raise an exception back to the caller. - If fileChanged Then - - ' Create the new .docx filename. - Dim newFileName = Path.ChangeExtension(fileName, ".docx") - - ' If it already exists, it will be deleted! - If File.Exists(newFileName) Then - File.Delete(newFileName) - End If - - ' Rename the file. - File.Move(fileName, newFileName) - End If -``` +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet6)] *** ## Sample Code -The following is the complete **ConvertDOCMtoDOCX** code sample in C\# and Visual +The following is the complete `ConvertDOCMtoDOCX` code sample in C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs)] +[!code-csharp[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb)] +[!code-vb[](../../samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb#snippet0)] +*** ## See also diff --git a/samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs b/samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs index 33a31ef4..c9d00033 100644 --- a/samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs +++ b/samples/word/convert_from_the_docm_to_the_docx_file_format/cs/Program.cs @@ -3,19 +3,27 @@ using System; using System.IO; +// ConvertDOCMtoDOCX(args[0]); +// // Given a .docm file (with macro storage), remove the VBA // project, reset the document type, and save the document with a new name. +// +// static void ConvertDOCMtoDOCX(string fileName) +// { + // bool fileChanged = false; using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true)) { // Access the main document part. var docPart = document.MainDocumentPart ?? throw new ArgumentNullException("MainDocumentPart is null."); + // + // // Look for the vbaProject part. If it is there, delete it. var vbaPart = docPart.VbaProjectPart; if (vbaPart is not null) @@ -23,17 +31,20 @@ static void ConvertDOCMtoDOCX(string fileName) // Delete the vbaProject part and then save the document. docPart.DeletePart(vbaPart); docPart.Document.Save(); + // + // // Change the document type to // not macro-enabled. - document.ChangeDocumentType( - WordprocessingDocumentType.Document); + document.ChangeDocumentType(WordprocessingDocumentType.Document); // Track that the document has been changed. fileChanged = true; + // } } + // // If anything goes wrong in this file handling, // the code will raise an exception back to the caller. if (fileChanged) @@ -50,4 +61,6 @@ static void ConvertDOCMtoDOCX(string fileName) // Rename the file. File.Move(fileName, newFileName); } -} \ No newline at end of file + // +} +// diff --git a/samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb b/samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb index f47f5c16..20aea40b 100644 --- a/samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb +++ b/samples/word/convert_from_the_docm_to_the_docx_file_format/vb/Program.vb @@ -4,21 +4,29 @@ Imports DocumentFormat.OpenXml.Packaging Module Program Sub Main(args As String()) + ' + ConvertDOCMtoDOCX(args(0)) + ' End Sub ' Given a .docm file (with macro storage), remove the VBA ' project, reset the document type, and save the document with a new name. + ' + ' Public Sub ConvertDOCMtoDOCX(ByVal fileName As String) + ' + ' Dim fileChanged As Boolean = False - Using document As WordprocessingDocument = - WordprocessingDocument.Open(fileName, True) + Using document As WordprocessingDocument = WordprocessingDocument.Open(fileName, True) ' Access the main document part. Dim docPart = document.MainDocumentPart + ' + ' ' Look for the vbaProject part. If it is there, delete it. Dim vbaPart = docPart.VbaProjectPart If vbaPart IsNot Nothing Then @@ -26,7 +34,9 @@ Module Program ' Delete the vbaProject part and then save the document. docPart.DeletePart(vbaPart) docPart.Document.Save() + ' + ' ' Change the document type to ' not macro-enabled. document.ChangeDocumentType( @@ -34,9 +44,11 @@ Module Program ' Track that the document has been changed. fileChanged = True + ' End If End Using + ' ' If anything goes wrong in this file handling, ' the code will raise an exception back to the caller. If fileChanged Then @@ -52,5 +64,7 @@ Module Program ' Rename the file. File.Move(fileName, newFileName) End If + ' End Sub + ' End Module \ No newline at end of file From 59fb086ff1e0fd547ff00e17386b7d2eb7be5e61 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Mon, 13 May 2024 16:40:56 -0700 Subject: [PATCH 14/53] closes #209 --- ...ackage-part-to-a-document-part-in-a-dif.md | 2 +- ...heme-part-in-a-word-processing-document.md | 2 +- ...rch-and-replace-text-in-a-document-part.md | 2 +- ...add-tables-to-word-processing-documents.md | 2 +- ...ientation-of-a-word-processing-document.md | 250 ++++-------------- .../cs/Program.cs | 61 +++-- .../vb/Program.vb | 53 +++- 7 files changed, 131 insertions(+), 241 deletions(-) diff --git a/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md b/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md index dbfbf88a..11d86267 100644 --- a/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md +++ b/docs/general/how-to-copy-the-contents-of-an-open-xml-package-part-to-a-document-part-in-a-dif.md @@ -33,7 +33,7 @@ programmatically. To open an existing document, instantiate the class as shown in the following two **using** statements. In the same statement, you open the word processing file with the specified -file name by using the [Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method, with the Boolean parameter. +file name by using the method, with the Boolean parameter. For the source file that set the parameter to **false** to open it for read-only access. For the target file, set the parameter to **true** in order to enable editing the document. diff --git a/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md b/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md index 5b499b48..41d38e3b 100644 --- a/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md +++ b/docs/general/how-to-replace-the-theme-part-in-a-word-processing-document.md @@ -29,7 +29,7 @@ In the sample code, you start by opening the word processing file by instantiating the class as shown in the following **using** statement. In the same statement, you open the word processing file *document* by using the -[Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method, with the Boolean parameter set + method, with the Boolean parameter set to **true** to enable editing the document. ### [C#](#tab/cs-0) diff --git a/docs/general/how-to-search-and-replace-text-in-a-document-part.md b/docs/general/how-to-search-and-replace-text-in-a-document-part.md index 9e57abad..d970c5fc 100644 --- a/docs/general/how-to-search-and-replace-text-in-a-document-part.md +++ b/docs/general/how-to-search-and-replace-text-in-a-document-part.md @@ -32,7 +32,7 @@ In the sample code, you start by opening the word processing file by instantiating the **** class as shown in the following **using** statement. In the same statement, you open the word processing file *document* by using the -**[Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open)** method, with the Boolean parameter set +**** method, with the Boolean parameter set to **true** to enable editing the document. ### [C#](#tab/cs-0) diff --git a/docs/word/how-to-add-tables-to-word-processing-documents.md b/docs/word/how-to-add-tables-to-word-processing-documents.md index e242dcc2..42342073 100644 --- a/docs/word/how-to-add-tables-to-word-processing-documents.md +++ b/docs/word/how-to-add-tables-to-word-processing-documents.md @@ -165,7 +165,7 @@ Before you can insert a table into a document, you must create the [Table](/dotn *** -The constructor for the **TableProperties** class allows you to specify as many child elements as you like (much like the [XElement](/dotnet/api/system.xml.linq.xelement) constructor). In this case, the code creates [TopBorder](/dotnet/api/documentformat.openxml.wordprocessing.topborder), [BottomBorder](/dotnet/api/documentformat.openxml.wordprocessing.bottomborder), [LeftBorder](/dotnet/api/documentformat.openxml.wordprocessing.leftborder), [RightBorder](/dotnet/api/documentformat.openxml.wordprocessing.rightborder), [InsideHorizontalBorder](/dotnet/api/documentformat.openxml.wordprocessing.insidehorizontalborder), and [InsideVerticalBorder](/dotnet/api/documentformat.openxml.wordprocessing.insideverticalborder) child elements, each describing one of the border elements for the table. For each element, the code sets the **Val** and **Size** properties as part of calling the constructor. Setting the size is simple, but setting the **Val** property requires a bit more effort: this property, for this particular object, represents the border style, and you must set it to an enumerated value. To do that, create an instance of the [EnumValue\](/dotnet/api/documentformat.openxml.enumvalue-1) generic type, passing the specific border type ([Single](/dotnet/api/documentformat.openxml.wordprocessing.bordervalues) as a parameter to the constructor. Once the code has set all the table border value it needs to set, it calls the [AppendChild\](/dotnet/api/documentformat.openxml.openxmlelement.appendchild) method of the table, indicating that the generic type is [TableProperties](/dotnet/api/ ocumentformat.openxml.wordprocessing.tableproperties)—that is, it is appending an instance of the **TableProperties** class, using the variable **props** as the value. +The constructor for the **TableProperties** class allows you to specify as many child elements as you like (much like the [XElement](/dotnet/api/system.xml.linq.xelement) constructor). In this case, the code creates [TopBorder](/dotnet/api/documentformat.openxml.wordprocessing.topborder), [BottomBorder](/dotnet/api/documentformat.openxml.wordprocessing.bottomborder), [LeftBorder](/dotnet/api/documentformat.openxml.wordprocessing.leftborder), [RightBorder](/dotnet/api/documentformat.openxml.wordprocessing.rightborder), [InsideHorizontalBorder](/dotnet/api/documentformat.openxml.wordprocessing.insidehorizontalborder), and [InsideVerticalBorder](/dotnet/api/documentformat.openxml.wordprocessing.insideverticalborder) child elements, each describing one of the border elements for the table. For each element, the code sets the **Val** and **Size** properties as part of calling the constructor. Setting the size is simple, but setting the **Val** property requires a bit more effort: this property, for this particular object, represents the border style, and you must set it to an enumerated value. To do that, create an instance of the generic type, passing the specific border type ([Single](/dotnet/api/documentformat.openxml.wordprocessing.bordervalues) as a parameter to the constructor. Once the code has set all the table border value it needs to set, it calls the [AppendChild\](/dotnet/api/documentformat.openxml.openxmlelement.appendchild) method of the table, indicating that the generic type is [TableProperties](/dotnet/api/ ocumentformat.openxml.wordprocessing.tableproperties)—that is, it is appending an instance of the **TableProperties** class, using the variable **props** as the value. ## Fill the table with data diff --git a/docs/word/how-to-change-the-print-orientation-of-a-word-processing-document.md b/docs/word/how-to-change-the-print-orientation-of-a-word-processing-document.md index 75bf8f58..0c614792 100644 --- a/docs/word/how-to-change-the-print-orientation-of-a-word-processing-document.md +++ b/docs/word/how-to-change-the-print-orientation-of-a-word-processing-document.md @@ -12,7 +12,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 05/13/2024 ms.localizationpriority: medium --- @@ -20,7 +20,7 @@ ms.localizationpriority: medium This topic shows how to use the classes in the Open XML SDK for Office to programmatically set the print orientation of a Microsoft Word document. It contains an example -**SetPrintOrientation** method to illustrate this task. +`SetPrintOrientation` method to illustrate this task. @@ -28,25 +28,17 @@ Office to programmatically set the print orientation of a Microsoft Word documen ## SetPrintOrientation Method -You can use the **SetPrintOrientation** method +You can use the `SetPrintOrientation` method to change the print orientation of a word processing document. The method accepts two parameters that indicate the name of the document to -modify (string) and the new print orientation ([PageOrientationValues](/dotnet/api/documentformat.openxml.wordprocessing.pageorientationvalues)). +modify (string) and the new print orientation (). -The following code shows the **SetPrintOrientation** method. +The following code shows the `SetPrintOrientation` method. ### [C#](#tab/cs-0) -```csharp - public static void SetPrintOrientation( - string fileName, PageOrientationValues newOrientation) -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Sub SetPrintOrientation( - ByVal fileName As String, - ByVal newOrientation As PageOrientationValues) -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet1)] *** @@ -59,21 +51,14 @@ the width, height, and margins for each section. ## Calling the Sample SetPrintOrientation Method -To call the sample **SetPrintOrientation** -method, pass a string that contains the name of the file to convert. The -following code shows an example method call. +To call the sample `SetPrintOrientation` +method, pass a string that contains the name of the file to convert and the string "landscape" or "portrait" +depending on which orientation you want. The following code shows an example method call. ### [C#](#tab/cs-1) -```csharp - SetPrintOrientation(@"C:\Users\Public\Documents\ChangePrintOrientation.docx", - PageOrientationValues.Landscape); -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - SetPrintOrientation("C:\Users\Public\Documents\ChangePrintOrientation.docx", - PageOrientationValues.Landscape) -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet2)] *** @@ -81,40 +66,22 @@ following code shows an example method call. ## How the Code Works -The following code first opens the document by using the [Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method and sets the **isEditable** parameter to -**true** to indicate that the document should +The following code first determines which orientation to apply and +then opens the document by using the +method and sets the `isEditable` parameter to +`true` to indicate that the document should be read/write. The code maintains a Boolean variable that tracks whether the document has changed (so that it can save the document later, if the document has changed). The code retrieves a reference to the main document part, and then uses that reference to retrieve a collection of -all of the descendants of type [SectionProperties](/dotnet/api/documentformat.openxml.wordprocessing.sectionproperties) within the content of the +all of the descendants of type within the content of the document. Later code will use this collection to set the orientation for each section in turn. ### [C#](#tab/cs-2) -```csharp - using (var document = - WordprocessingDocument.Open(fileName, true)) - { - bool documentChanged = false; - - var docPart = document.MainDocumentPart; - var sections = docPart.Document.Descendants(); - // Code removed here... - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - Using document = - WordprocessingDocument.Open(fileName, True) - Dim documentChanged As Boolean = False - - Dim docPart = document.MainDocumentPart - Dim sections = docPart.Document.Descendants(Of SectionProperties)() - ' Code removed here... - End Using -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet3)] *** @@ -122,35 +89,12 @@ each section in turn. ## Iterating Through All the Sections -The next block of code iterates through all the sections in the collection of **SectionProperties** elements. For each section, the code initializes a variable that tracks whether the page orientation for the section was changed so the code can update the page size and margins. (If the new orientation matches the original orientation, the code will not update the page.) The code continues by retrieving a reference to the first [PageSize](/dotnet/api/documentformat.openxml.wordprocessing.pagesize) descendant of the **SectionProperties** element. If the reference is not null, the code updates the orientation as required. +The next block of code iterates through all the sections in the collection of `SectionProperties` elements. For each section, the code initializes a variable that tracks whether the page orientation for the section was changed so the code can update the page size and margins. (If the new orientation matches the original orientation, the code will not update the page.) The code continues by retrieving a reference to the first descendant of the `SectionProperties` element. If the reference is not null, the code updates the orientation as required. ### [C#](#tab/cs-3) -```csharp - foreach (SectionProperties sectPr in sections) - { - bool pageOrientationChanged = false; - - PageSize pgSz = sectPr.Descendants().FirstOrDefault(); - if (pgSz != null) - { - // Code removed here... - } - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - For Each sectPr As SectionProperties In sections - - Dim pageOrientationChanged As Boolean = False - - Dim pgSz As PageSize = - sectPr.Descendants(Of PageSize).FirstOrDefault - If pgSz IsNot Nothing Then - ' Code removed here... - End If - Next -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet4)] *** @@ -158,61 +102,26 @@ The next block of code iterates through all the sections in the collection of ** ## Setting the Orientation for the Section -The next block of code first checks whether the [Orient](/dotnet/api/documentformat.openxml.wordprocessing.pagesize.orient) property of the **PageSize** element exists. As with many properties +The next block of code first checks whether the +property of the `PageSize` element exists. As with many properties of Open XML elements, the property or attribute might not exist yet. In that case, retrieving the property returns a null reference. By default, if the property does not exist, and the new orientation is Portrait, the -code will not update the page. If the **Orient** property already exists, and its value +code will not update the page. If the `Orient` property already exists, and its value differs from the new orientation value supplied as a parameter to the -method, the code sets the **Value** property of -the **Orient** property, and sets both the -**pageOrientationChanged** and the **documentChanged** flags. (The code uses the **pageOrientationChanged** flag to determine whether it -must update the page size and margins. It uses the **documentChanged** flag to determine whether it must +method, the code sets the `Value` property of +the `Orient` property, and sets both the +`pageOrientationChanged` and the `documentChanged` flags. (The code uses the `pageOrientationChanged` flag to determine whether it +must update the page size and margins. It uses the `documentChanged` flag to determine whether it must save the document at the end.) > [!NOTE] -> If the code must create the **Orient** property, it must also create the value to store in the property, as a new [EnumValue\](/dotnet/api/documentformat.openxml.enumvalue-1) instance, supplying the new orientation in the **EnumValue** constructor. +> If the code must create the `Orient` property, it must also create the value to store in the property, as a new instance, supplying the new orientation in the `EnumValue` constructor. ### [C#](#tab/cs-4) -```csharp - if (pgSz.Orient == null) - { - if (newOrientation != PageOrientationValues.Portrait) - { - pageOrientationChanged = true; - documentChanged = true; - pgSz.Orient = - new EnumValue(newOrientation); - } - } - else - { - if (pgSz.Orient.Value != newOrientation) - { - pgSz.Orient.Value = newOrientation; - pageOrientationChanged = true; - documentChanged = true; - } - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - If pgSz.Orient Is Nothing Then - If newOrientation <> PageOrientationValues.Portrait Then - pageOrientationChanged = True - documentChanged = True - pgSz.Orient = - New EnumValue(Of PageOrientationValues)(newOrientation) - End If - Else - If pgSz.Orient.Value <> newOrientation Then - pgSz.Orient.Value = newOrientation - pageOrientationChanged = True - documentChanged = True - End If - End If -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet5)] *** @@ -224,34 +133,12 @@ At this point in the code, the page orientation may have changed. If so, the code must complete two more tasks. It must update the page size, and update the page margins for the section. The first task is easy—the following code just swaps the page height and width, storing the values -in the **PageSize** element. +in the `PageSize` element. ### [C#](#tab/cs-5) -```csharp - if (pageOrientationChanged) - { - // Changing the orientation is not enough. You must also - // change the page size. - var width = pgSz.Width; - var height = pgSz.Height; - pgSz.Width = height; - pgSz.Height = width; - // Code removed here... - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - If pageOrientationChanged Then - ' Changing the orientation is not enough. You must also - ' change the page size. - Dim width = pgSz.Width - Dim height = pgSz.Height - pgSz.Width = height - pgSz.Height = width - ' Code removed here... - End If -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet6)] *** @@ -261,53 +148,17 @@ in the **PageSize** element. The next step in the sample procedure handles margins for the section. If the page orientation has changed, the code must rotate the margins to -match. To do so, the code retrieves a reference to the [PageMargin](/dotnet/api/documentformat.openxml.wordprocessing.pagemargin) element for the section. If the -element exists, the code rotates the margins. Note that the code rotates +match. To do so, the code retrieves a reference to the element for the section. If the element exists, the code rotates the margins. Note that the code rotates the margins by 90 degrees—some printers rotate the margins by 270 degrees instead and you could modify the code to take that into account. -Also be aware that the [Top](/dotnet/api/documentformat.openxml.wordprocessing.pagemargin.top) and [Bottom](/dotnet/api/documentformat.openxml.wordprocessing.pagemargin.bottom) properties of the **PageMargin** object are signed values, and the -[Left](/dotnet/api/documentformat.openxml.wordprocessing.pagemargin.left) and [Right](/dotnet/api/documentformat.openxml.wordprocessing.pagemargin.right) properties are unsigned values. The -code must convert between the two types of values as it rotates the +Also be aware that the and properties of the `PageMargin` object are signed values, and the + and properties are unsigned values. The code must convert between the two types of values as it rotates the margin settings, as shown in the following code. ### [C#](#tab/cs-6) -```csharp - PageMargin pgMar = - sectPr.Descendants().FirstOrDefault(); - if (pgMar != null) - { - var top = pgMar.Top.Value; - var bottom = pgMar.Bottom.Value; - var left = pgMar.Left.Value; - var right = pgMar.Right.Value; - - pgMar.Top = new Int32Value((int)left); - pgMar.Bottom = new Int32Value((int)right); - pgMar.Left = - new UInt32Value((uint)System.Math.Max(0, bottom)); - pgMar.Right = - new UInt32Value((uint)System.Math.Max(0, top)); - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - Dim pgMar As PageMargin = - sectPr.Descendants(Of PageMargin).FirstOrDefault() - If pgMar IsNot Nothing Then - Dim top = pgMar.Top.Value - Dim bottom = pgMar.Bottom.Value - Dim left = pgMar.Left.Value - Dim right = pgMar.Right.Value - - pgMar.Top = CType(left, Int32Value) - pgMar.Bottom = CType(right, Int32Value) - pgMar.Left = CType(System.Math.Max(0, - CType(bottom, Int32Value)), UInt32Value) - pgMar.Right = CType(System.Math.Max(0, - CType(top, Int32Value)), UInt32Value) - End If -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet7)] *** @@ -319,19 +170,9 @@ After all the modifications, the code determines whether the document has changed. If the document has changed, the code saves it. ### [C#](#tab/cs-7) -```csharp - if (documentChanged) - { - docPart.Document.Save(); - } -``` - +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet8)] ### [Visual Basic](#tab/vb-7) -```vb - If documentChanged Then - docPart.Document.Save() - End If -``` +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet8)] *** @@ -339,14 +180,15 @@ has changed. If the document has changed, the code saves it. ## Sample Code -The following is the complete **SetPrintOrientation** code sample in C\# and Visual +The following is the complete `SetPrintOrientation` code sample in C\# and Visual Basic. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs)] +[!code-csharp[](../../samples/word/change_the_print_orientation/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb)] +[!code-vb[](../../samples/word/change_the_print_orientation/vb/Program.vb#snippet0)] +*** ----------------------------------------------------------------------------- diff --git a/samples/word/change_the_print_orientation/cs/Program.cs b/samples/word/change_the_print_orientation/cs/Program.cs index fa990838..4d9ca6cc 100644 --- a/samples/word/change_the_print_orientation/cs/Program.cs +++ b/samples/word/change_the_print_orientation/cs/Program.cs @@ -1,49 +1,62 @@ -#nullable enable - using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System; +using System.Collections.Generic; using System.Linq; +// SetPrintOrientation(args[0], args[1]); +// // Given a document name, set the print orientation for // all the sections of the document. -static void SetPrintOrientation(string fileName, string no) +// +// +static void SetPrintOrientation(string fileName, string orientation) + // { - PageOrientationValues newOrientation = no.ToLower() switch + // + PageOrientationValues newOrientation = orientation.ToLower() switch { "landscape" => PageOrientationValues.Landscape, "portrait" => PageOrientationValues.Portrait, - _ => throw new System.ArgumentException("Invalid argument: " + no) + _ => throw new System.ArgumentException("Invalid argument: " + orientation) }; - using (var document = - WordprocessingDocument.Open(fileName, true)) + using (var document = WordprocessingDocument.Open(fileName, true)) { bool documentChanged = false; - if (document.MainDocumentPart is null) + if (document?.MainDocumentPart?.Document.Body is null) { throw new ArgumentNullException("MainDocumentPart and/or Body is null."); } - var docPart = document.MainDocumentPart; + Body docBody = document.MainDocumentPart.Document.Body; + IEnumerable sections = docBody.ChildElements.OfType(); - var sections = docPart.Document.Descendants(); + if (sections.Count() == 0) + { + docBody.AddChild(new SectionProperties()); + sections = docBody.ChildElements.OfType(); + } + // + + // foreach (SectionProperties sectPr in sections) { bool pageOrientationChanged = false; - PageSize pgSz = sectPr.Descendants().First(); + PageSize pgSz = sectPr.ChildElements.OfType().FirstOrDefault() ?? sectPr.AppendChild(new PageSize() { Width = 12240, Height = 15840 }); // No Orient property? Create it now. Otherwise, just - // set its value. Assume that the default orientation - // is Portrait. + // set its value. Assume that the default orientation is Portrait. + // if (pgSz.Orient is null) + // { // Need to create the attribute. You do not need to // create the Orient property if the property does not @@ -53,8 +66,7 @@ static void SetPrintOrientation(string fileName, string no) { pageOrientationChanged = true; documentChanged = true; - pgSz.Orient = - new EnumValue(newOrientation); + pgSz.Orient = new EnumValue(newOrientation); } } else @@ -67,7 +79,9 @@ static void SetPrintOrientation(string fileName, string no) pageOrientationChanged = true; documentChanged = true; } + // + // if (pageOrientationChanged) { // Changing the orientation is not enough. You must also @@ -76,8 +90,10 @@ static void SetPrintOrientation(string fileName, string no) var height = pgSz.Height; pgSz.Width = height; pgSz.Height = width; + // - PageMargin pgMar = (sectPr.Descendants().FirstOrDefault()) ?? throw new ArgumentNullException("There are no PageMargin elements in the section."); + // + PageMargin? pgMar = sectPr.Descendants().FirstOrDefault(); if (pgMar is not null) { @@ -98,17 +114,20 @@ static void SetPrintOrientation(string fileName, string no) pgMar.Top = new Int32Value((int)left); pgMar.Bottom = new Int32Value((int)right); - pgMar.Left = - new UInt32Value((uint)System.Math.Max(0, bottom)); - pgMar.Right = - new UInt32Value((uint)System.Math.Max(0, top)); + pgMar.Left = new UInt32Value((uint)System.Math.Max(0, bottom)); + pgMar.Right = new UInt32Value((uint)System.Math.Max(0, top)); } + // } } } + + // if (documentChanged) { - docPart.Document.Save(); + document.MainDocumentPart.Document.Save(); } + // } } +// \ No newline at end of file diff --git a/samples/word/change_the_print_orientation/vb/Program.vb b/samples/word/change_the_print_orientation/vb/Program.vb index 587b64ae..dba52b5c 100644 --- a/samples/word/change_the_print_orientation/vb/Program.vb +++ b/samples/word/change_the_print_orientation/vb/Program.vb @@ -4,28 +4,52 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module Program Sub Main(args As String()) + ' + SetPrintOrientation(args(0), args(1)) + ' End Sub ' Given a document name, set the print orientation for ' all the sections of the document. - Public Sub SetPrintOrientation( - ByVal fileName As String, ByVal newOrientation As PageOrientationValues) - Using document = - WordprocessingDocument.Open(fileName, True) + + ' + ' + Public Sub SetPrintOrientation(ByVal fileName As String, ByVal orientation As String) + ' + + ' + Dim newOrientation As PageOrientationValues + + Select Case orientation + Case "landscape" + newOrientation = PageOrientationValues.Landscape + Case "portrait" + newOrientation = PageOrientationValues.Portrait + Case Else + Throw New ArgumentException("Invalid orientation") + End Select + + + Using document = WordprocessingDocument.Open(fileName, True) Dim documentChanged As Boolean = False Dim docPart = document.MainDocumentPart Dim sections = docPart.Document.Descendants(Of SectionProperties)() + ' + ' For Each sectPr As SectionProperties In sections Dim pageOrientationChanged As Boolean = False - Dim pgSz As PageSize = - sectPr.Descendants(Of PageSize).FirstOrDefault + Dim pgSz As PageSize = sectPr.Descendants(Of PageSize).FirstOrDefault + + ' If pgSz IsNot Nothing Then + ' + ' No Orient property? Create it now. Otherwise, just ' set its value. Assume that the default orientation ' is Portrait. @@ -49,7 +73,9 @@ Module Program documentChanged = True End If End If + ' + ' If pageOrientationChanged Then ' Changing the orientation is not enough. You must also ' change the page size. @@ -57,9 +83,10 @@ Module Program Dim height = pgSz.Height pgSz.Width = height pgSz.Height = width + ' - Dim pgMar As PageMargin = - sectPr.Descendants(Of PageMargin).FirstOrDefault() + ' + Dim pgMar As PageMargin = sectPr.Descendants(Of PageMargin).FirstOrDefault() If pgMar IsNot Nothing Then ' Rotate margins. Printer settings control how far you ' rotate when switching to landscape mode. Not having those @@ -73,18 +100,20 @@ Module Program pgMar.Top = CType(left, Int32Value) pgMar.Bottom = CType(right, Int32Value) - pgMar.Left = CType(System.Math.Max(0, - CType(bottom, Int32Value)), UInt32Value) - pgMar.Right = CType(System.Math.Max(0, - CType(top, Int32Value)), UInt32Value) + pgMar.Left = CType(System.Math.Max(0, CType(bottom, Int32Value)), UInt32Value) + pgMar.Right = CType(System.Math.Max(0, CType(top, Int32Value)), UInt32Value) End If + ' End If End If Next + ' If documentChanged Then docPart.Document.Save() End If + ' End Using End Sub + ' End Module \ No newline at end of file From c1de6cbc9160686de74d6eb7a31494c9a1644ac9 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Tue, 14 May 2024 11:00:07 -0700 Subject: [PATCH 15/53] closes #208 --- ...n-a-table-in-a-word-processing-document.md | 116 ++++++------------ .../word/change_text_a_table/cs/Program.cs | 16 ++- .../word/change_text_a_table/vb/Program.vb | 13 +- 3 files changed, 58 insertions(+), 87 deletions(-) diff --git a/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md b/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md index bc951426..d59a555c 100644 --- a/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md +++ b/docs/word/how-to-change-text-in-a-table-in-a-word-processing-document.md @@ -11,7 +11,7 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 11/01/2017 +ms.date: 05/14/2024 ms.localizationpriority: high --- @@ -23,40 +23,28 @@ This topic shows how to use the Open XML SDK for Office to programmatically chan ## Open the Existing Document -To open an existing document, instantiate the class as shown in the following **using** statement. In the same statement, open the word processing file at the specified **filepath** by using the **Open** method, with the Boolean parameter set to **true** to enable editing the document. +To open an existing document, instantiate the class as shown in the following `using` statement. In the same statement, open the word processing file at the specified `filepath` by using the `Open` method, with the Boolean parameter set to `true` to enable editing the document. ### [C#](#tab/cs-0) -```csharp - using (WordprocessingDocument doc = - WordprocessingDocument.Open(filepath, true)) - { - // Insert other code here. - } -``` - +[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Using doc As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) - ' Insert other code here. - End Using -``` +[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb#snippet1)] *** [!include[Using Statement](../includes/using-statement.md)] ## The Structure of a Table -The basic document structure of a **WordProcessingML** document consists of the **document** and **body** -elements, followed by one or more block level elements such as **p**, which represents a paragraph. A paragraph -contains one or more **r** elements. The **r** stands for run, which is a region of text with +The basic document structure of a `WordProcessingML` document consists of the `document` and `body` +elements, followed by one or more block level elements such as `p`, which represents a paragraph. A paragraph +contains one or more `r` elements. The `r` stands for run, which is a region of text with a common set of properties, such as formatting. A run contains one or -more **t** elements. The **t** element contains a range of text. +more `t` elements. The `t` element contains a range of text. -The document might contain a table as in this example. A **table** is a set of paragraphs (and other block-level -content) arranged in **rows** and **columns**. Tables in **WordprocessingML** are defined via the **tbl** element, which is analogous to the HTML table -tag. Consider an empty one-cell table (that is, a table with one row and +The document might contain a table as in this example. A `table` is a set of paragraphs (and other block-level +content) arranged in `rows` and `columns`. Tables in `WordprocessingML` are defined via the `tbl` element, which is analogous to the HTML table tag. Consider an empty one-cell table (that is, a table with one row and one column) and 1 point borders on all sides. This table is represented -by the following **WordprocessingML** code +by the following `WordprocessingML` code example. ```xml @@ -85,43 +73,23 @@ example. ``` This table specifies table-wide properties of 100% of page width using -the **tblW** element, a set of table borders -using the **tblBorders** element, the table +the `tblW` element, a set of table borders +using the `tblBorders` element, the table grid, which defines a set of shared vertical edges within the table -using the **tblGrid** element, and a single -table row using the **tr** element. +using the `tblGrid` element, and a single +table row using the `tr` element. ## How the Sample Code Works -In the sample code, after you open the document in the **using** statement, you locate the first table in +In the sample code, after you open the document in the `using` statement, you locate the first table in the document. Then you locate the second row in the table by finding the row whose index is 1. Next, you locate the third cell in that row whose index is 2, as shown in the following code example. ### [C#](#tab/cs-1) -```csharp - // Find the first table in the document. - Table table = - doc.MainDocumentPart.Document.Body.Elements().First(); - - // Find the second row in the table. - TableRow row = table.Elements().ElementAt(1); - - // Find the third cell in the row. - TableCell cell = row.Elements().ElementAt(2); -``` - +[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - ' Find the first table in the document. - Dim table As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table)().First() - - ' Find the second row in the table. - Dim row As TableRow = table.Elements(Of TableRow)().ElementAt(1) - - ' Find the third cell in the row. - Dim cell As TableCell = row.Elements(Of TableCell)().ElementAt(2) -``` +[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb#snippet2)] *** @@ -130,20 +98,9 @@ first paragraph of the cell and replace the text with the passed in text. The following code example shows these actions. ### [C#](#tab/cs-2) -```csharp - Paragraph p = cell.Elements().First(); - Run r = p.Elements().First(); - Text t = r.Elements().First(); - t.Text = txt; -``` - +[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - Dim p As Paragraph = cell.Elements(Of Paragraph)().First() - Dim r As Run = p.Elements(Of Run)().First() - Dim t As Text = r.Elements(Of Text)().First() - t.Text = txt -``` +[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb#snippet3)] *** @@ -152,55 +109,52 @@ text. The following code example shows these actions. The following code example shows how to change the text in the specified table cell in a word processing document. The code example expects that the document, whose file name and path are passed as an argument to the -**ChangeTextInCell** method, contains a table. +`ChangeTextInCell` method, contains a table. The code example also expects that the table has at least two rows and three columns, and that the table contains text in the cell that is located at the second row and the third column position. When you call -the **ChangeTextInCell** method in your +the `ChangeTextInCell` method in your program, the text in the cell at the specified location will be replaced -by the text that you pass in as the second argument to the **ChangeTextInCell** method. In the following table -the text "The text from the API example" was used. +by the text that you pass in as the second argument to the `ChangeTextInCell` method. | **Some text** | **Some text** | **Some text** | |---------------|---------------|---------------| -| Some text | Some text |The text from the API example | +| Some text | Some text |The text from the second argument | ## Sample Code -The **ChangeTextinCell** method changes the +The `ChangeTextInCell` method changes the text in the second row and the third column of the first table found in the file. You call it by passing a full path to the file as the first parameter, and the text to use as the second parameter. For example, the -following call to the **ChangeTextInCell** +following call to the `ChangeTextInCell` method changes the text in the specified cell to "The text from the API example." ### [C#](#tab/cs-3) -```csharp - ChangeTextInCell(@"c:\Users\Public\Documents\word4.docx", - "The text from the API example"); -``` - +[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ChangeTextInCell("C:\Users\Public\Documents\word4.docx", _ - "The text from the API example") -``` +[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb#snippet4)] *** Following is the complete code example. ### [C#](#tab/cs) -[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs)] +[!code-csharp[](../../samples/word/change_text_a_table/cs/Program.cs#snippet0)] ### [Visual Basic](#tab/vb) -[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb)] +[!code-vb[](../../samples/word/change_text_a_table/vb/Program.vb#snippet0)] +*** ## See also [Open XML SDK class library reference](/office/open-xml/open-xml-sdk) + [How to: Change Text in a Table in a Word Processing Document](/previous-versions/office/developer/office-2010/cc840870(v=office.14)) + [Language-Integrated Query (LINQ)](/previous-versions/bb397926(v=vs.140)) + [Extension Methods (C\# Programming Guide)](/dotnet/csharp/programming-guide/classes-and-structs/extension-methods) + [Extension Methods (Visual Basic)](/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods) diff --git a/samples/word/change_text_a_table/cs/Program.cs b/samples/word/change_text_a_table/cs/Program.cs index f90b3714..b3a269db 100644 --- a/samples/word/change_text_a_table/cs/Program.cs +++ b/samples/word/change_text_a_table/cs/Program.cs @@ -2,21 +2,26 @@ using DocumentFormat.OpenXml.Wordprocessing; using System; using System.Linq; - +// ChangeTextInCell(args[0], args[1]); +// +// // Change the text in a table in a word processing document. static void ChangeTextInCell(string filePath, string txt) { // Use the file name and path passed in as an argument to - // open an existing document. + // open an existing document. + // using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true)) + // { if (doc.MainDocumentPart is null || doc.MainDocumentPart.Document.Body is null) { throw new ArgumentNullException("MainDocumentPart and/or Body is null."); } + // // Find the first table in the document. Table table = doc.MainDocumentPart.Document.Body.Elements
().First(); @@ -25,7 +30,8 @@ static void ChangeTextInCell(string filePath, string txt) // Find the third cell in the row. TableCell cell = row.Elements().ElementAt(2); - + // + // // Find the first paragraph in the table cell. Paragraph p = cell.Elements().First(); @@ -35,5 +41,7 @@ static void ChangeTextInCell(string filePath, string txt) // Set the text for the run. Text t = r.Elements().First(); t.Text = txt; + // } -} \ No newline at end of file +} +// \ No newline at end of file diff --git a/samples/word/change_text_a_table/vb/Program.vb b/samples/word/change_text_a_table/vb/Program.vb index f7508208..61b922ea 100644 --- a/samples/word/change_text_a_table/vb/Program.vb +++ b/samples/word/change_text_a_table/vb/Program.vb @@ -3,15 +3,21 @@ Imports DocumentFormat.OpenXml.Wordprocessing Module Program Sub Main(args As String()) + ' + ChangeTextInCell(args(0), args(1)) + ' End Sub - + ' ' Change the text in a table in a word processing document. Public Sub ChangeTextInCell(ByVal filepath As String, ByVal txt As String) ' Use the file name and path passed in as an argument to ' Open an existing document. + ' Using doc As WordprocessingDocument = WordprocessingDocument.Open(filepath, True) + ' + ' ' Find the first table in the document. Dim table As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table)().First() @@ -20,7 +26,8 @@ Module Program ' Find the third cell in the row. Dim cell As TableCell = row.Elements(Of TableCell)().ElementAt(2) - + ' + ' ' Find the first paragraph in the table cell. Dim p As Paragraph = cell.Elements(Of Paragraph)().First() @@ -30,6 +37,8 @@ Module Program ' Set the text for the run. Dim t As Text = r.Elements(Of Text)().First() t.Text = txt + ' End Using End Sub + ' End Module \ No newline at end of file From 0cf5f64e943b8ac2601b78f6f839d356fa47f240 Mon Sep 17 00:00:00 2001 From: Michael Bowen Date: Tue, 10 Sep 2024 16:23:35 -0700 Subject: [PATCH 16/53] closes #207 --- ...paragraph-in-a-word-processing-document.md | 473 +++--------------- .../cs/Program.cs | 34 +- .../vb/Program.vb | 36 +- 3 files changed, 122 insertions(+), 421 deletions(-) diff --git a/docs/word/how-to-apply-a-style-to-a-paragraph-in-a-word-processing-document.md b/docs/word/how-to-apply-a-style-to-a-paragraph-in-a-word-processing-document.md index 94fe5f23..4373d951 100644 --- a/docs/word/how-to-apply-a-style-to-a-paragraph-in-a-word-processing-document.md +++ b/docs/word/how-to-apply-a-style-to-a-paragraph-in-a-word-processing-document.md @@ -10,30 +10,24 @@ ms.suite: office ms.author: o365devx author: o365devx ms.topic: conceptual -ms.date: 06/28/2021 +ms.date: 06/27/2024 ms.localizationpriority: high --- # Apply a style to a paragraph in a word processing document -This topic shows how to use the classes in the Open XML SDK for Office to programmatically apply a style to a paragraph within a word processing document. It contains an example **ApplyStyleToParagraph** method to illustrate this task, plus several supplemental example methods to check whether a style exists, add a new style, and add the styles part. +This topic shows how to use the classes in the Open XML SDK for Office to programmatically apply a style to a paragraph within a word processing document. It contains an example `ApplyStyleToParagraph` method to illustrate this task, plus several supplemental example methods to check whether a style exists, add a new style, and add the styles part. ## ApplyStyleToParagraph method -The **ApplyStyleToParagraph** example method can be used to apply a style to a paragraph. You must first obtain a reference to the document as well as a reference to the paragraph that you want to style. The method accepts four parameters that indicate: the reference to the opened word processing document, the styleid of the style to be applied, the name of the style to be applied, and the reference to the paragraph to which to apply the style. +The `ApplyStyleToParagraph` example method can be used to apply a style to a paragraph. You must first obtain a reference to the document as well as a reference to the paragraph that you want to style. The method accepts four parameters that indicate: the path to the word processing document to open, the styleid of the style to be applied, the name of the style to be applied, and the reference to the paragraph to which to apply the style. ### [C#](#tab/cs-0) -```csharp - public static void ApplyStyleToParagraph(WordprocessingDocument doc, string styleid, string stylename, Paragraph p) -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet1)] ### [Visual Basic](#tab/vb-0) -```vb - Public Sub ApplyStyleToParagraph(ByVal doc As WordprocessingDocument, - ByVal styleid As String, ByVal stylename As String, ByVal p As Paragraph) -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet1)] *** @@ -43,24 +37,12 @@ The following sections in this topic explain the implementation of this method a The Sample Code section also shows the code required to set up for calling the sample method. To use the method to apply a style to a paragraph in a document, you first need a reference to the open document. In the Open XML SDK, the class represents a Word document package. To open and work with a Word document, create an instance of the class from the document. After you create the instance, use it to obtain access to the main document part that contains the text of the document. The content in the main document part is represented in the package as XML using WordprocessingML markup. -To create the class instance, call one of the overloads of the [Open()](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) method. The following sample code shows how to use the [WordprocessingDocument.Open](/dotnet/api/documentformat.openxml.packaging.wordprocessingdocument.open) overload. The first parameter takes a string that represents the full path to the document to open. The second parameter takes a value of **true** or **false** and represents whether to open the file for editing. In this example the parameter is **true** to enable read/write access to the file. +To create the class instance, call one of the overloads of the method. The following sample code shows how to use the overload. The first parameter takes a string that represents the full path to the document to open. The second parameter takes a value of `true` or `false` and represents whether to open the file for editing. In this example the parameter is `true` to enable read/write access to the file. ### [C#](#tab/cs-1) -```csharp - using (WordprocessingDocument doc = - WordprocessingDocument.Open(fileName, true)) - { - // Code removed here. - } -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet2)] ### [Visual Basic](#tab/vb-1) -```vb - Using doc As WordprocessingDocument = _ - WordprocessingDocument.Open(fileName, True) - ' Code removed here. - End Using -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet2)] *** @@ -68,43 +50,22 @@ To create the class instance, call one of the overloads of the [Open()](/dotnet/ ## Get the paragraph to style -After opening the file, the sample code retrieves a reference to the first paragraph. Because a typical word processing document body contains many types of elements, the code filters the descendants in the body of the document to those of type **Paragraph**. The [ElementAtOrDefault](/dotnet/api/system.linq.enumerable.elementatordefault) method is then employed to retrieve a reference to the paragraph. Because the elements are indexed starting at zero, you pass a zero to retrieve the reference to the first paragraph, as shown in the following code example. +After opening the file, the sample code retrieves a reference to the first paragraph. Because a typical word processing document body contains many types of elements, the code filters the descendants in the body of the document to those of type `Paragraph`. The method is then employed to retrieve a reference to the paragraph. Because the elements are indexed starting at zero, you pass a zero to retrieve the reference to the first paragraph, as shown in the following code example. ### [C#](#tab/cs-2) -```csharp - // Get the first paragraph. - Paragraph p = - doc.MainDocumentPart.Document.Body.Descendants() - .ElementAtOrDefault(0); - - // Check for a null reference. - if (p == null) - { - // Code removed here… - } -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet3)] ### [Visual Basic](#tab/vb-2) -```vb - Dim p = doc.MainDocumentPart.Document.Body.Descendants(Of Paragraph)() _ - .ElementAtOrDefault(0) - - ' Check for a null reference. - If p Is Nothing Then - ' Code removed here. - End If -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet3)] *** -The reference to the found paragraph is stored in a variable named p. If -a paragraph is not found at the specified index, the -[ElementAtOrDefault](/dotnet/api/system.linq.enumerable.elementatordefault) +The reference to the found paragraph is stored in a variable named paragraph. If +a paragraph is not found at the specified index, the method returns null as the default value. This provides an opportunity to test for null and throw an error with an appropriate error message. Once you have the references to the document and the paragraph, you can -call the **ApplyStyleToParagraph** example +call the `ApplyStyleToParagraph` example method to do the remaining work. To call the method, you pass the reference to the document as the first parameter, the styleid of the style to apply as the second parameter, the name of the style as the @@ -119,17 +80,17 @@ child element of the paragraph and includes a set of properties that allow you to specify the formatting for the paragraph. The following information from the ISO/IEC 29500 specification -introduces the **pPr** (paragraph properties) +introduces the `pPr` (paragraph properties) element used for specifying the formatting of a paragraph. Note that section numbers preceded by § are from the ISO specification. Within the paragraph, all rich formatting at the paragraph level is -stored within the **pPr** element (§17.3.1.25; §17.3.1.26). [Note: Some +stored within the `pPr` element (§17.3.1.25; §17.3.1.26). [Note: Some examples of paragraph properties are alignment, border, hyphenation override, indentation, line spacing, shading, text direction, and widow/orphan control. -Among the properties is the **pStyle** element +Among the properties is the `pStyle` element to specify the style to apply to the paragraph. For example, the following sample markup shows a pStyle element that specifies the "OverdueAmount" style. @@ -143,35 +104,17 @@ following sample markup shows a pStyle element that specifies the ``` -In the Open XML SDK, the **pPr** element is -represented by the [ParagraphProperties](/dotnet/api/documentformat.openxml.wordprocessing.paragraphproperties) class. The code +In the Open XML SDK, the `pPr` element is +represented by the class. The code determines if the element exists, and creates a new instance of the -**ParagraphProperties** class if it does not. -The **pPr** element is a child of the **p** (paragraph) element; consequently, the [PrependChild\(T)](/dotnet/api/documentformat.openxml.openxmlelement.prependchild) method is used to add +`ParagraphProperties` class if it does not. +The `pPr` element is a child of the `p` (paragraph) element; consequently, the method is used to add the instance, as shown in the following code example. ### [C#](#tab/cs-3) -```csharp - // If the paragraph has no ParagraphProperties object, create one. - if (p.Elements().Count() == 0) - { - p.PrependChild(new ParagraphProperties()); - } - - // Get the paragraph properties element of the paragraph. - ParagraphProperties pPr = p.Elements().First(); -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet4)] ### [Visual Basic](#tab/vb-3) -```vb - ' If the paragraph has no ParagraphProperties object, create one. - If p.Elements(Of ParagraphProperties)().Count() = 0 Then - p.PrependChild(Of ParagraphProperties)(New ParagraphProperties()) - End If - - ' Get the paragraph properties element of the paragraph. - Dim pPr As ParagraphProperties = p.Elements(Of ParagraphProperties)().First() -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet4)] *** @@ -190,65 +133,23 @@ following code verifies that the styles part exists, and creates it if it does not. ### [C#](#tab/cs-4) -```csharp - // Get the Styles part for this document. - StyleDefinitionsPart part = - doc.MainDocumentPart.StyleDefinitionsPart; - - // If the Styles part does not exist, add it and then add the style. - if (part == null) - { - part = AddStylesPartToPackage(doc); - // Code removed here... - } -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet5)] ### [Visual Basic](#tab/vb-4) -```vb - ' Get the Styles part for this document. - Dim part As StyleDefinitionsPart = doc.MainDocumentPart.StyleDefinitionsPart - - ' If the Styles part does not exist, add it and then add the style. - If part Is Nothing Then - part = AddStylesPartToPackage(doc) - ' Code removed here... - End If -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet5)] *** -The **AddStylesPartToPackage** example method -does the work of adding the styles part. It creates a part of the **StyleDefinitionsPart** type, adding it as a child -to the main document part. The code then appends the **Styles** root element, which is the parent element -that contains all of the styles. The **Styles** -element is represented by the [Styles](/dotnet/api/documentformat.openxml.wordprocessing.styles) class in the Open XML SDK. Finally, +The `AddStylesPartToPackage` example method +does the work of adding the styles part. It creates a part of the `StyleDefinitionsPart` type, adding it as a child +to the main document part. The code then appends the `Styles` root element, which is the parent element +that contains all of the styles. The `Styles` +element is represented by the class in the Open XML SDK. Finally, the code saves the part. ### [C#](#tab/cs-5) -```csharp - // Add a StylesDefinitionsPart to the document. Returns a reference to it. - public static StyleDefinitionsPart AddStylesPartToPackage(WordprocessingDocument doc) - { - StyleDefinitionsPart part; - part = doc.MainDocumentPart.AddNewPart(); - Styles root = new Styles(); - root.Save(part); - return part; - } -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet6)] ### [Visual Basic](#tab/vb-5) -```vb - ' Add a StylesDefinitionsPart to the document. Returns a reference to it. - Public Function AddStylesPartToPackage(ByVal doc As WordprocessingDocument) _ - As StyleDefinitionsPart - Dim part As StyleDefinitionsPart - part = doc.MainDocumentPart.AddNewPart(Of StyleDefinitionsPart)() - Dim root As New Styles() - root.Save(part) - Return part - End Function -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet6)] *** @@ -261,73 +162,26 @@ Styles are stored in the styles part, therefore if the styles part does not exist, the style itself cannot exist. If the styles part exists, the code verifies a matching style by calling -the **IsStyleIdInDocument** example method and +the `IsStyleIdInDocument` example method and passing the document and the styleid. If no match is found on styleid, -the code then tries to lookup the styleid by calling the **GetStyleIdFromStyleName** example method and +the code then tries to lookup the styleid by calling the `GetStyleIdFromStyleName` example method and passing it the style name. If the style does not exist, either because the styles part did not exist, or because the styles part exists, but the style does not, the -code calls the **AddNewStyle** example method +code calls the `AddNewStyle` example method to add the style. ### [C#](#tab/cs-6) -```csharp - // Get the Styles part for this document. - StyleDefinitionsPart part = - doc.MainDocumentPart.StyleDefinitionsPart; - - // If the Styles part does not exist, add it and then add the style. - if (part == null) - { - part = AddStylesPartToPackage(doc); - AddNewStyle(part, styleid, stylename); - } - else - { - // If the style is not in the document, add it. - if (IsStyleIdInDocument(doc, styleid) != true) - { - // No match on styleid, so let's try style name. - string styleidFromName = GetStyleIdFromStyleName(doc, stylename); - if (styleidFromName == null) - { - AddNewStyle(part, styleid, stylename); - } - else - styleid = styleidFromName; - } - } -``` - +[!code-csharp[](../../samples/word/apply_a_style_to_a_paragraph/cs/Program.cs#snippet7)] ### [Visual Basic](#tab/vb-6) -```vb - ' Get the Styles part for this document. - Dim part As StyleDefinitionsPart = doc.MainDocumentPart.StyleDefinitionsPart - - ' If the Styles part does not exist, add it and then add the style. - If part Is Nothing Then - part = AddStylesPartToPackage(doc) - AddNewStyle(part, styleid, stylename) - Else - ' If the style is not in the document, add it. - If IsStyleIdInDocument(doc, styleid) <> True Then - ' No match on styleid, so let's try style name. - Dim styleidFromName As String = - GetStyleIdFromStyleName(doc, stylename) - If styleidFromName Is Nothing Then - AddNewStyle(part, styleid, stylename) - Else - styleid = styleidFromName - End If - End If - End If -``` +[!code-vb[](../../samples/word/apply_a_style_to_a_paragraph/vb/Program.vb#snippet7)] *** -Within the **IsStyleInDocument** example -method, the work begins with retrieving the **Styles** element through the **Styles** property of the [StyleDefinitionsPart](/dotnet/api/documentformat.openxml.packaging.maindocumentpart.styledefinitionspart) of the main document +Within the `IsStyleInDocument` example +method, the work begins with retrieving the `Styles` element through the `Styles` property of the + of the main document part, and then determining whether any styles exist as children of that element. All style elements are stored as children of the styles element. @@ -336,81 +190,34 @@ If styles do exist, the code looks for a match on the styleid. The styleid is an attribute of the style that is used in many places in the document to refer to the style, and can be thought of as its primary identifier. Typically you use the styleid to identify a style in code. -The -[FirstOrDefault](/dotnet/api/system.linq.enumerable.firstordefault) +The method defaults to null if no match is found, so the code verifies for null to see whether a style was matched, as shown in the following excerpt. ### [C#](#tab/cs-7) -```csharp - // Return true if the style id is in the document, false otherwise. - public static bool IsStyleIdInDocument(WordprocessingDocument doc, - string styleid) - { - // Get access to the Styles element for this document. - Styles s = doc.MainDocumentPart.StyleDefinitionsPart.Styles; - - // Check that there are styles and how many. - int n = s.Elements