Include \t Switch in a TOC Field in Word Document to Ignore Outline Levels \u using C# .NET

Using Aspose.Words for .NET 9.5.0. I have inserted three different table of contents (TOC) into my document. Before saving the document I call doc.UpdateFields() and then doc.Save(filename, SaveFormat.Doc). The first table of contents is generated correctly. However, the second and third come out as a hybrid of the first and themselves. If I do a “Update entire table” (in Word 2007) the second and third TOC are corrected. Have you ever heard of this problem before? Any suggestions?

My TOC code is:

builder.InsertTableOfContents("\\o \"1-2\" \\t \"Heading 4,1\" \\x");
builder.InsertTableOfContents("\\u \\t \"Heading 4,1\" \\x");
builder.InsertTableOfContents("\\u \\t \"Heading 3,1\"");

Thanks.

Hi Rob,
Thanks for your inquiry.
Can you please attach your document here for testing and we will provide you with some further information.
Thanks,

Attached is the file, and below is a sample of the code I used.

Please let me know.

// Passing no document to the DocumentBuilder will cause a blank document to be created.
DocumentBuilder builder1 = new DocumentBuilder();

// Get the document used by the DocumentBuilder.
Document doc1 = builder1.Document;

// Insert a table of contents at the beginning of the document.
builder1.InsertTableOfContents("\o "
    1 - 2 " \t "
    Heading 4, 1 " \x");
builder1.InsertBreak(BreakType.PageBreak);
builder1.InsertTableOfContents("\u \t "
    Heading 4, 1 " \x");
builder1.InsertBreak(BreakType.PageBreak);
builder1.InsertTableOfContents("\u \t "
    Heading 3, 1 "");
builder1.InsertBreak(BreakType.PageBreak);
// Build a document with complex structure by applying different heading styles thus creating TOC entries.

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 1.1");
builder1.Writeln("Heading 1.2");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 2");
builder1.Writeln("Heading 3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading3;

builder1.Writeln("Heading 3.1.1");
builder1.Writeln("Heading 3.1.2");
builder1.Writeln("Heading 3.1.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading4;

builder1.Writeln("Heading 3.1.3.1");
builder1.InsertBreak(BreakType.PageBreak);

builder1.Writeln("Heading 3.1.3.2");
builder1.Writeln("Heading 3.1.3.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.2");
builder1.Writeln("Heading 3.3");

doc1.UpdateFields();
doc1.UpdatePageLayout();

doc1.Save("test.doc"), SaveFormat.Doc);

Would it be possible to call range.updatefields() on selected sections/ranges in the document. Looking at the documentation it seems like it might be possible, but I am not sure how to set a range to particular section.

Hi Rob,
Thanks for this additional information.
I managed to reproduce the issue on my side. You’re request has been logged and you will be informed when it’s fixed.
In the mean time you can remove the “\u” switch from the second and third TOC and the generated output appears as expected.
Regarding updating the fields of a certain range, this is of course possible. In your case you would want to use section breaks though and then update the fields of a particular section. For example please see the code below:

Section section = doc.FirstSection;
section.Range.UpdateFields();

This will update only the fields found in the first section of the document. Please note that UpdatePageLayout cannot be executed over a particular range.
Thanks,

Figured out how to make new sections. Also removing the /u from the table of contents solves the population problem. Below is the code with changes in bold. Deletions are in red, bold, and underlined.

Thanks for the help.

// Passing no document to the DocumentBuilder will cause a blank document to be created.
DocumentBuilder builder1 = new DocumentBuilder();

// Get the document used by the DocumentBuilder.
Document doc1 = builder1.Document;

// Insert a table of contents at the beginning of the document.
builder1.InsertTableOfContents("\\o \"1-2\" \\t \"Heading4,1\" \\x");
builder1.InsertBreak(BreakType.SectionBreakNewPage);

builder1.InsertTableOfContents("\\u \\t \"Heading4,1\" \\x");
builder1.InsertBreak(BreakType.SectionBreakNewPage);

builder1.InsertTableOfContents("\\u \\t \"Heading3,1\"");
builder1.InsertBreak(BreakType.SectionBreakNewPage);

// Build a document with complex structure by applying different heading styles thus creating TOC entries.

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 1.1");
builder1.Writeln("Heading 1.2");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 2");
builder1.Writeln("Heading 3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading3;

builder1.Writeln("Heading 3.1.1");
builder1.Writeln("Heading 3.1.2");
builder1.Writeln("Heading 3.1.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading4;

builder1.Writeln("Heading 3.1.3.1");
builder1.InsertBreak(BreakType.PageBreak);

builder1.Writeln("Heading 3.1.3.2");
builder1.Writeln("Heading 3.1.3.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.2");
builder1.Writeln("Heading 3.3");

doc1.Sections[0].Range.UpdateFields();
doc1.Sections[1].Range.UpdateFields();
doc1.Sections[2].Range.UpdateFields();
doc1.UpdatePageLayout();

doc1.Save("test.doc", SaveFormat.Doc);

How do I pick each of the sections except from the first one. In may actual document, I have multiple sections. The sections I containing the TOC are in the middle of the document, so using doc.FirstSection will not work.

I thought about trying to use int section1Index = Section.IndexOf(), but that does not seem possible, as I need to have a parameter for the function, but not sure what to use.

Any ideas?

Thanks.

Hi Rob,
Thanks for your inquiry.
You can retrieve any section in the document by using the index property, for example.

Section section = doc.Sections[1];

You can also retrieve all but the first section by using code like below.

foreach(Section section in doc.Sections)
{
    if (section != doc.FirstSection)
    {
        // Code here
    }
}

If you have any further queries, please feel free to ask.
Thanks,

Actually that is not what I needed. I need to know what the index of a given section is. To find that out one must use this bit of code:

int index = doc.Sections.IndexOf(builder.CurrentSection)

(found in another post after digging around for a while: Word sections and page breaks problem when i am appending dynamic data)
With that information I am able to populate an array. Then, right before saving the document, I run through that array and UpdateFields() of the sections containing the TOC’s. Below is my code.
Thanks!

// Passing no document to the DocumentBuilder will cause a blank document to be created.
DocumentBuilder builder1 = new DocumentBuilder();
// Get the document used by the DocumentBuilder.
Document doc1 = builder1.Document;  // TOC Section Index and List of these indices
int index = -1;
List tocSectionIndices = new List();
// Insert a table of contents at the beginning of the document.
builder1.InsertTableOfContents("\\o \"1-2\" \\t \"Heading4,1\" \\x");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
builder1.InsertBreak(BreakType.SectionBreakNewPage);
builder1.InsertTableOfContents("\\t \"Heading4,1\" \\x");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
builder1.InsertBreak(BreakType.SectionBreakNewPage);
builder1.InsertTableOfContents("\\t \"Heading3,1\"");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
builder1.InsertBreak(BreakType.SectionBreakNewPage);
// Build a document with complex structure by applying different heading styles thus creating TOC entries.
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
builder1.Writeln("Heading 1");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
builder1.Writeln("Heading 1.1");
builder1.Writeln("Heading 1.2");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
builder1.Writeln("Heading 2");
builder1.Writeln("Heading 3");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
builder1.Writeln("Heading 3.1");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading3;
builder1.Writeln("Heading 3.1.1");
builder1.Writeln("Heading 3.1.2");
builder1.Writeln("Heading 3.1.3");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading4;
builder1.Writeln("Heading 3.1.3.1");
builder1.InsertBreak(BreakType.PageBreak);
builder1.Writeln("Heading 3.1.3.2");
builder1.Writeln("Heading 3.1.3.3");
builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
builder1.Writeln("Heading 3.2");
builder1.Writeln("Heading 3.3");  // If one has to add content to the document before generating the TOC,
// then its best to pass the List of TOC section indices. I have to call
// UpdateFields () in another function.
foreach (int index in tocSectionIndices)
{
    doc1.Sections[index].Range.UpdateFields();
}

doc1.UpdatePageLayout();
doc1.Save("test.doc", SaveFormat.Doc);

Hi Rob,
Thanks for this additional information.
That code will work nicely. If you have any further queries, please feel free to ask.
Thanks,

Now I need to apply styles to my TOC. I’ve made a function based on suggestions of previous threads:

private void SetTocStylingForWord(Document doc)
{
    Aspose.Words.Style toc1 = doc.Styles[StyleIdentifier.Toc1];
    Aspose.Words.Style toc2 = doc.Styles[StyleIdentifier.Toc2];
    Aspose.Words.Style toc3 = doc.Styles[StyleIdentifier.Toc3];
    Aspose.Words.Style toc4 = doc.Styles[StyleIdentifier.Toc4];

    Aspose.Words.Style[] tocStyles = {
        toc1,
        toc2,
        toc3,
        toc4
    };
    foreach(Aspose.Words.Style style in tocStyles)
    {
        style.Font.Name = "Times New Roman";
        style.Font.Size = 12;
        style.Font.Bold = false;
    }

    toc3.Font.Size = 10;
}

I’ve inserted this function in several locations without avail. I have placed it in each TOC section and even right before I call the update function. The stylings I have created are NOT applied. HOWEVER, if I manually do an “Update entire table” in the produced Word document, my stylings take affect. Go figure.

Any suggestions, please?

Thanks.

// Passing no document to the DocumentBuilder will cause a blank document to be created.
DocumentBuilder builder1 = new DocumentBuilder();

// Get the document used by the DocumentBuilder.
Document doc1 = builder1.Document;

// TOC Section Index and List of these indices
int index = -1;
List tocSectionIndices = new List();

// Insert a table of contents at the beginning of the document.
builder1.InsertTableOfContents("\\o \"1-2\" \\t \"Heading4,1\" \\x");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
SetTocStylingForWord(doc);
builder1.InsertBreak(BreakType.SectionBreakNewPage);

builder1.InsertTableOfContents("\\t \"Heading4,1\" \\x");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
SetTocStylingForWord(doc);

builder1.InsertBreak(BreakType.SectionBreakNewPage);

builder1.InsertTableOfContents("\\t \"Heading3,1\"");
index = doc.Sections.IndexOf(builder.CurrentSection);
tocSectionIndices.Add(index);
SetTocStylingForWord(doc);

builder1.InsertBreak(BreakType.SectionBreakNewPage);

// Build a document with complex structure by applying different heading styles thus creating TOC entries.

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 1.1");
builder1.Writeln("Heading 1.2");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;

builder1.Writeln("Heading 2");
builder1.Writeln("Heading 3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.1");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading3;

builder1.Writeln("Heading 3.1.1");
builder1.Writeln("Heading 3.1.2");
builder1.Writeln("Heading 3.1.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading4;

builder1.Writeln("Heading 3.1.3.1");
builder1.InsertBreak(BreakType.PageBreak);

builder1.Writeln("Heading 3.1.3.2");
builder1.Writeln("Heading 3.1.3.3");

builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;

builder1.Writeln("Heading 3.2");
builder1.Writeln("Heading 3.3");

// If one has to add content to the document before generating the TOC,
// then its best to pass the List of TOC section indices. I have to call
// UpdateFields () in another function.
foreach (int index in tocSectionIndices)
{
    doc1.Sections[index].Range.UpdateFields();
}


SetTocStylingForWord(doc);
doc1.UpdatePageLayout();

doc1.Save("test.doc", SaveFormat.Doc);

Hi Rob,
Thanks for your inquiry.
I cannot reproduce the issue on my side, formatting on the TOC is changed when the method is called in any part of your code. Are you able to attach your template documents here and perhaps create a sample application which demonstrates the issue?
Thanks,

OK, I have figured out why this is happening. I have changed the styling of headers with the below functions. The TOC’s follow the styling set forth in the below functions instead of the styling I have set for each TOC. So in a nut shell how do we prevent the header style from affecting the TOC style? Any idea on how to isolate the TOC’s from the styling applied to the headers? Below is my modified code, so you can get the same results that have.

Thanks!

{
    Document doc1 = new Document();
    DocumentBuilder builder1 = new DocumentBuilder(doc1);

    // TOC Section Index and List of these indices
    int index1 = -1;
    List tocSectionIndices1 = new List();

    // Insert a table of contents at the beginning of the document.
    builder1.InsertTableOfContents("\\o \"1-2\" \\t \"Heading4,1\" \\x");
    index1 = doc1.Sections.IndexOf(builder1.CurrentSection);
    tocSectionIndices1.Add(index1);
    SetTocStylingForWord(doc1);
    builder1.InsertBreak(BreakType.SectionBreakNewPage);

    builder1.InsertTableOfContents("\\t \"Heading4,1\" \\x");
    index1 = doc1.Sections.IndexOf(builder1.CurrentSection);
    tocSectionIndices1.Add(index1);
    SetTocStylingForWord(doc1);
    builder1.InsertBreak(BreakType.SectionBreakNewPage);

    builder1.InsertTableOfContents("\\t \"Heading3,3\"");
    index1 = doc1.Sections.IndexOf(builder1.CurrentSection);
    tocSectionIndices1.Add(index1);
    SetTocStylingForWord(doc1);
    builder1.InsertBreak(BreakType.SectionBreakNewPage);

    // Build a document with complex structure by applying different heading styles thus creating TOC entries.

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
    SetHeading1ForWord(builder1);
    builder1.Writeln("Heading 1");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
    SetHeading2ForWord(builder1);
    builder1.Writeln("Heading 1.1");
    builder1.Writeln("Heading 1.2");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
    SetHeading1ForWord(builder1);

    builder1.Writeln("Heading 2");
    builder1.Writeln("Heading 3");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
    SetHeading2ForWord(builder1);

    builder1.Writeln("Heading 3.1");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading3;
    SetHeading3ForWord(builder1);

    builder1.Writeln("Heading 3.1.1");
    builder1.Writeln("Heading 3.1.2");
    builder1.Writeln("Heading 3.1.3");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading4;
    SetHeading4ForWord(builder1);

    builder1.Writeln("Heading 3.1.3.1");
    builder1.InsertBreak(BreakType.PageBreak);

    builder1.Writeln("Heading 3.1.3.2");
    builder1.Writeln("Heading 3.1.3.3");

    // builder1.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading2;
    SetHeading2ForWord(builder1);

    builder1.Writeln("Heading 3.2");
    builder1.Writeln("Heading 3.3");

    foreach (int index2 in tocSectionIndices1)
    {
        doc1.Sections[index2].Range.UpdateFields();
    }

    SetTocStylingForWord(doc1);
    doc1.UpdatePageLayout();

    doc1.Save("test.doc", SaveFormat.Doc);
}

private void SetHeading1ForWord(DocumentBuilder builder)
{
    try
    {
        builder.ParagraphFormat.StyleName = "Heading 1";
        builder.ParagraphFormat.Alignment = ParagraphAlignment.Left;
        builder.Font.Size = 13.5;
        builder.Font.Bold = true;
        builder.Font.Name = "Times New Roman";
        builder.ParagraphFormat.SpaceAfterAuto = true;
    }
    catch (Exception ex)
    {
        _Logger.Error("An unexpected error occurred while setting the heading level 1 for Word document", ex);

        throw;
    }
}

private void SetHeading2ForWord(DocumentBuilder builder)
{
    try
    {
        builder.ParagraphFormat.StyleName = "Heading 2";
        builder.Font.Size = 12;
        builder.Font.Bold = true;
        builder.Font.Italic = false;
        builder.Font.Name = "Times New Roman";
        builder.ParagraphFormat.SpaceAfterAuto = true;
    }
    catch (Exception ex)
    {
        _Logger.Error("An unexpected error occurred while setting the heading level 2 for Word document.", ex);

        throw;
    }
}

private void SetHeading3ForWord(DocumentBuilder builder)
{
    try
    {
        builder.ParagraphFormat.StyleName = "Heading 3";
        builder.Font.Size = 11;
        builder.Font.Bold = true;
        builder.Font.Name = "Times New Roman";
        builder.ParagraphFormat.SpaceAfterAuto = true;
    }
    catch (Exception ex)
    {
        _Logger.Error("An unexpected error occurred while setting the heading level 3 for Word document.", ex);

        throw;
    }
}

private void SetHeading4ForWord(DocumentBuilder builder)
{
    try
    {
        builder.ParagraphFormat.StyleName = "Heading 4";
        builder.Font.Size = 13.5;
        builder.Font.Bold = true;
        builder.Font.Name = "Times New Roman";
        builder.ParagraphFormat.SpaceAfterAuto = true;
    }
    catch (Exception ex)
    {
        _Logger.Error("An unexpected error occurred while setting the heading level 4 for Word document.", ex);

        throw;
    }
}

private void SetTocStylingForWord(Document doc)
{
    try
    {
        Aspose.Words.Style toc1 = doc.Styles[StyleIdentifier.Toc1];
        Aspose.Words.Style toc2 = doc.Styles[StyleIdentifier.Toc2];
        Aspose.Words.Style toc3 = doc.Styles[StyleIdentifier.Toc3];
        Aspose.Words.Style toc4 = doc.Styles[StyleIdentifier.Toc4];

        Aspose.Words.Style[] tocStyles = {
            toc1,
            toc2,
            toc3,
            toc4
        };
        foreach (Aspose.Words.Style style in tocStyles)
        {
            style.Font.Name = "Times New Roman";
            style.Font.Size = 12;
            style.Font.Bold = false;
        }

        toc3.Font.Size = 10;
    }
    catch (Exception ex)
    {
        _Logger.Error("An unexpected error occurred while setting table of contents styling for Word document.", ex);

        throw;
    }
}

Hi Rob,
Thanks for this additional information.
This occurs because direct formatting on a heading will be included in entries in the TOC. If you update the TOC in MS Word you should see the same effect.
Instead when inserting each heading title you should apply the formatting to the style of each heading, instead of directly onto the inserted text. Please see the code below. These changes need to be made for all of your SetHeadingXForWord methods.

private static void SetHeading1ForWord(DocumentBuilder builder)
{
    Style headingStyle = builder.Document.Styles[StyleIdentifier.Heading1];
    headingStyle.ParagraphFormat.Alignment = ParagraphAlignment.Left;
    headingStyle.Font.Size = 13.5;
    headingStyle.Font.Bold = true;
    headingStyle.Font.Name = "Times New Roman";
    headingStyle.ParagraphFormat.SpaceAfterAuto = true;
    builder.ParagraphFormat.StyleName = "Heading 1";
}

Thanks,

Sorta worked. Works in the code I provided you, but not my actual code. I will have to tweak it when I get back on Monday. For my actual code, the contents of the TOC still match what the header style is set to. F9 in the word document will force it to the actual TOC style…

ARG!

What is the difference in applying Styles using doc.Styles[StyleIdentifier.Toc1] where doc is a Document, and builder.Document.Styles[StyleIdentifier.Toc1] where builder is DocumentBuilder? Should both of these produce the same results when used in the context of Style toc1 = X?

Also, after a header or TOC style has been set is it necessary to call the SetXForWord(), or can I just call builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.X before the section to be modified? Basically, is once the toc, header, or body text styles is changed is that constant throughout the document?

Thank you.

Hi Rob,
Thanks for your inquiry.
As long as the document referenced by the builder is the same document then the two calls are identical. To clarify, a builder does actions on the current document linked to it through DocumentBuilder.Document. As long as the builder is correctly linked to your document then the two calls are in affect doing the exact same thing.
Please see the code below for a short demonstration.

Document doc = new Document();
Document doc2 = new Document();
// Changes property of TOC1 style in doc.
doc.Styles[StyleIdentifier.Toc1].Font.Name = "Arial";
DocumentBuilder builder = new DocumentBuilder(doc);
// Also changes a property of TOC1 style in doc
builder.Document.Styles[StyleIdentifier.Toc1].Font.Size = 12;
builder.Document = doc2;
// The reference document in the builder has been changed. The style will now be changed in doc2 instead of doc
builder.Document.Styles[StyleIdentifier.Toc1].Font.Bold = true;

Regarding your other query, sure you can set the the properties for a style once and then just reference that style in the text you want. The styles properties will be automatically applied.
Thanks,

The issues you have found earlier (filed as WORDSNET-4230) have been fixed in this .NET update and in this Java update.

This message was posted using Notification2Forum from Downloads module by aspose.notifier.