This project has moved and is read-only. For the latest updates, please go here.

Is there a way to create an Index?

Jan 30, 2014 at 5:43 AM
I'm generating a big document but I need to create an Index in page 2 after all document has been completed, is there a way I can do this?

I really like this project but I still need some feature like this one (the Index) and the ability to copy tables at specific place at the document, everything else is great good work :)
Feb 10, 2014 at 2:13 AM
So I found a way to create an Index, you just have to create an empty Index, save it in the template you are going to use then you have to update a setting in the XML document, this setting will make Word ask you to update the table of contents the first time the document is opened in that way you end up with an automatically created Index, for the code you can use Eric's White code along with the explanation, it is really simple you can find it here:

http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/08/exploring-tables-of-contents-in-open-xml-wordprocessingml-documents.aspx

He also have an entire series dedicated to the subject, and it could be an interesting add to this library, the ability to insert an Index and update the setting XML.

Regards
Marked as answer by drverboten on 2/9/2014 at 6:13 PM
Feb 10, 2014 at 7:21 AM
Feel free to submit the patch. I will happily integrate it for you :-)
Mar 28, 2014 at 5:35 AM
Hi, sorry for the late response, I just uploaded the patch files for solution I found for the TOC, any questions or changes, please let me know. Patch ID: 16114

Regards
Mar 30, 2014 at 12:16 PM
Could you provide example on how to use it exactly and maybe UnitTests?
Aug 11, 2014 at 3:04 PM
Pleas provide an example.
Sep 10, 2014 at 1:11 PM
Was there any further movement on this issue?
  1. Does it work?
  2. What would it take to get it mainlined? Examples and unit tests?
Sep 10, 2014 at 1:30 PM
@benhysell

Examples and unit tests would be good. Right now what it does or how the process seems to be working when I last looked at a it (i may be off on this so keep in mind that I've not tested this) is "add 5 or so files" to source code. Create a TOC based template, and use that template. After using that template in DocX it would be populated automatically.

To me this solution seems to be a little bit short for implementation. I would guess we need at least:
a) a way to create a TOC from within DocX
b) force an update of TOC (which is what the current functionality does right?)
c) multiple choices of TOC to change how it looks.

Unit tests, description, examples on how it works also prefered.
Sep 10, 2014 at 2:03 PM
@MadBoy

Thanks for the quick reply! I saw the thread was a bit old and wanted to see where things stood before starting to poke around the code.
Oct 9, 2014 at 7:28 PM
I played around with the patch, and it certainly works as advertised.
  1. Add all three files from the patch to the solution
  2. Add a reference to DocumentFormat.OpenXml.dll, I just grabbed a version from NuGet
  3. Create a template document that has an empty Table of Contents (TOC) in the document.
  4. With DocX work with the template document, i.e. insert text, pictures, headings, etc.
  5. Save the DocX document.
  6. Call private static void AddTocUpdateSetting(String filepath), which will re-open the file, and add the parameter <w:updateFields w:val="true" /> to the file.
When a user opens your newly created document they will be presented with a modal dialog box asking them if they would like all of the fields in the document updated. If they click yes, the TOC will be updated.

I found a second method to accomplish the same results with much less code, see http://www.samuraiprogrammer.com/blog/2010/08/09/OpenXMLHowToRefreshAFieldWhenTheDocumentIsOpened.aspx. Same exact idea, use a template that has a TOC in it, work with your document, save your document, and then lastly insert an UpdateFields value. The code to do this is a single function, see below.
private static void AddTocUpdateSetting(String filepath)
        {

            using (WordprocessingDocument document = WordprocessingDocument.Open(filepath, true))
            {

                DocumentSettingsPart settingsPart =
                    document.MainDocumentPart.GetPartsOfType<DocumentSettingsPart>().First();

                // Create object to update fields on open
                UpdateFieldsOnOpen updateFields = new UpdateFieldsOnOpen();
                updateFields.Val = new DocumentFormat.OpenXml.OnOffValue(true);

                // Insert object into settings part.
                settingsPart.Settings.PrependChild<UpdateFieldsOnOpen>(updateFields);
                settingsPart.Settings.Save();

            }
        }
The advantage here is the solution is a single function, with much less code to maintain. The only rub with this solution is the modal dialog box is still presented to the user when they open the document.

There are two other methods I have found to ensure the TOC is updated and the user is not presented with a modal dialog box.

Method 1 - This method requires you to have a full copy of Word on the computer and uses Word Automation, see http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/22/exploring-tables-of-contents-in-openxml-wordprocessingml-documents-part-4.aspx. For my use case this is not desirable.

Method 2 - Do not use the UpdateFields method and use a macro in your template document, see http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/24/updating-the-toc-in-a-wordprocessingml-document-using-an-autoopen-macro.aspx.

The macro solution works well thus far in my testing.
Apr 23, 2015 at 8:58 AM
Hello together,

i'm sorry, i didn't like your solution proposals as I use docx to not have a need to include the open sdk. (But it took me to this solution 95% of the way, so thanks!)

I found out DocX can actually do that easily with just a few minor changes to the code.

To accomplish that goal add the following lines to DocX.cs into the class:
        /// <summary>
        /// Activate Updating Fields on Open
        /// </summary>
        public void UpdateFieldsOnOpen()
        {
            XElement element = new XElement(XName.Get("updateFields", DocX.w.NamespaceName));
            element.Add(new XAttribute(XName.Get("val", DocX.w.NamespaceName), "true"));

            settings.Root.AddFirst(element);
        }
Finally you need to modify the save process slightly because docx reloads the settings part directly before saving the document.
// Comment out or remove those lines:
-            using (TextReader tr = new StreamReader(settingsPart.GetStream()))
-                settings = XDocument.Load(tr);
// Insert this instead:
+            if (settings == null )
+            {
+                using (TextReader tr = new StreamReader(settingsPart.GetStream()))
+                    settings = XDocument.Load(tr);
+            }
Use these lines to use the new option:
docx.UpdateFieldsOnOpen();
docx.Save();
As a result, word will tell you that some fields need updating when you open the document.
Well after you bypassed that new preview mode that they put into word to complicate usage. Which i know everybody at my workplace loves very much.

It works on my computer :).
I hope it will help YOU ALL TOO since you are great people that deserve TOCs.

Best regards,
shoff
Apr 23, 2015 at 9:01 AM
As a result, word will tell you that some fields need updating when you open the document.
Well after you bypassed that new preview mode that they put into word to complicate usage. Which i know everybody at my workplace loves very much.
A little correction:
Yes, word will tell you. And word will ask you if you want to update all fields. You click yes. And then you get your TOC completly updated.

Best regards,
shoff