0

I am trying to implement multilevel list in word document programmatically using openxml sdk v2.5 and C#. I have used the following code in order to display headings in multilevel list. I am calling the AddHeading method and passing the respective parameters as shown below. My expected result is to be as below.

1.  Parent
    1.1. childItem
      1.1.1. subchildItem
    1.2. childItem
2.  Parent
    2.1. childItem
3.  Parent

But the output i am getting is

1. Parent
    1. childItem
      1. subchildItem
    2. childItem
2.  Parent
    1. childItem
3.  Parent
public static void AddHeading(WordprocessingDocument document, string colorVal, int fontSizeVal, string styleId, string styleName, string headingText, int numLvlRef, int numIdVal)
        {
            StyleRunProperties styleRunProperties = new StyleRunProperties();
            Color color = new Color() { Val = colorVal };
            DocumentFormat.OpenXml.Wordprocessing.FontSize fontSize1 = new DocumentFormat.OpenXml.Wordprocessing.FontSize();
            fontSize1.Val = new StringValue(fontSizeVal.ToString());

            styleRunProperties.Append(color);
            styleRunProperties.Append(fontSize1);
            AddStyleToDoc(document.MainDocumentPart.Document.MainDocumentPart, styleId, styleName, styleRunProperties, document);

            Paragraph p = new Paragraph();
            ParagraphProperties pp = new ParagraphProperties();
            pp.ParagraphStyleId = new ParagraphStyleId() { Val = styleId };
            pp.SpacingBetweenLines = new SpacingBetweenLines() { After = "0" };

            ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "ListParagraph" };
            NumberingProperties numberingProperties1 = new NumberingProperties();
            NumberingLevelReference numberingLevelReference1 = new NumberingLevelReference() { Val = numLvlRef };

            NumberingId numberingId1 = new NumberingId() { Val = numIdVal }; //Val is 1, 2, 3 etc based on your numberingid in your numbering element

            numberingProperties1.Append(numberingLevelReference1); Indentation indentation1 = new Indentation() { FirstLineChars = 0 };
            numberingProperties1.Append(numberingId1);
            pp.Append(paragraphStyleId1);
            pp.Append(numberingProperties1);
            pp.Append(indentation1);
            p.Append(pp);
            Run r = new Run();
            Text t = new Text(headingText) { Space = SpaceProcessingModeValues.Preserve };
            r.Append(t);
            p.Append(r);

            document.MainDocumentPart.Document.Body.Append(p);
        }


      public static void AddStyleToDoc(MainDocumentPart mainPart, string styleid, string stylename, StyleRunProperties styleRunProperties, WordprocessingDocument document)
        {
            StyleDefinitionsPart part = mainPart.StyleDefinitionsPart;
            if (part == null)
            {
                part = AddStylesPartToPackage(mainPart);
                AddNewStyle(part, styleid, stylename, styleRunProperties);
            }
            else
            {
                if (IsStyleIdInDocument(mainPart, styleid) != true)
                {
                    string styleidFromName = GetStyleIdFromStyleName(document, stylename);
                    if (styleidFromName == null)
                    {
                        AddNewStyle(part, styleid, stylename, styleRunProperties);
                    }
                    else
                        styleid = styleidFromName;
                }
            }
        }

        public static string GetStyleIdFromStyleName(WordprocessingDocument doc, string styleName)
        {
            StyleDefinitionsPart stylePart = doc.MainDocumentPart.StyleDefinitionsPart;
            string styleId = stylePart.Styles.Descendants<StyleName>()
                .Where(s => s.Val.Value.Equals(styleName) &&
                    (((Style)s.Parent).Type == StyleValues.Paragraph))
                .Select(n => ((Style)n.Parent).StyleId).FirstOrDefault();

            return styleId;
        }

        public static StyleDefinitionsPart AddStylesPartToPackage(MainDocumentPart mainPart)
        {
            StyleDefinitionsPart part;
            part = mainPart.AddNewPart<StyleDefinitionsPart>();
            DocumentFormat.OpenXml.Wordprocessing.Styles root = new DocumentFormat.OpenXml.Wordprocessing.Styles();
            root.Save(part);
            return part;
        }

        public static bool IsStyleIdInDocument(MainDocumentPart mainPart, string styleid)
        {
            DocumentFormat.OpenXml.Wordprocessing.Styles s = mainPart.StyleDefinitionsPart.Styles;

            int n = s.Elements<DocumentFormat.OpenXml.Wordprocessing.Style>().Count();
            if (n == 0)
                return false;

            DocumentFormat.OpenXml.Wordprocessing.Style style = s.Elements<DocumentFormat.OpenXml.Wordprocessing.Style>()
                .Where(st => (st.StyleId == styleid) && (st.Type == StyleValues.Paragraph))
                .FirstOrDefault();
            if (style == null)
                return false;

            return true;
        }

        private static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename, StyleRunProperties styleRunProperties)
        {
            DocumentFormat.OpenXml.Wordprocessing.Styles styles = styleDefinitionsPart.Styles;

            DocumentFormat.OpenXml.Wordprocessing.Style style = new DocumentFormat.OpenXml.Wordprocessing.Style()
            {
                Type = StyleValues.Paragraph,
                StyleId = styleid,
                CustomStyle = false
            };
            style.Append(new StyleName() { Val = stylename });
            style.Append(new BasedOn() { Val = "Normal" });
            style.Append(new NextParagraphStyle() { Val = "Normal" });
            style.Append(new UIPriority() { Val = 900 });

            styles.Append(style);
        }

Cindy Meister
  • 25,071
  • 21
  • 34
  • 43
svg
  • 9
  • 2
  • As best I can tell, this code is defining only 1 (the first) numbering level. If you want to use three numbering levels, all must be defined, including what information to be used from a previous numbering level. My recommendation would be to create such a style in a new Word document, using the tools in the UI. Save it, close and open in the Open XML SDK Productivity Tool. That will you the code necessary to create the document. – Cindy Meister Dec 12 '19 at 17:21
  • Or, alternatively, save the starting point document, create the style, save that to a different file name. Open the first in the Productivity Tool, then use the Compare feature for the second. That will give you the code to create the second document from the first. – Cindy Meister Dec 12 '19 at 17:21
  • @CindyMeister, unfortunately, styles alone won't do the job. You need a numbering definitions part in which the multi-level list is specified. Using Microsoft Word, you would either create (1) a multi-level list and link each required level to a style or (2) a list style. The key pieces of information (e.g., numbering formats) for the multi-level list are defined in the numbering definitions part in both cases. – Thomas Barnekow Dec 14 '19 at 17:24
  • @ThomasBarnekow In my book, numbering defintions *are* styles. Looking in the Productivity Tool would reveal exaclty which `Part` types are required for what someone needs. And... On Stack Overflow, if you've already answered a question (or know of an answer on the site) a question should be flagged/closed as a "Duplicate", not answered in brief with links. – Cindy Meister Dec 15 '19 at 06:10
  • Does this answer your question? [How do you create multi-level ordered lists with Open XML in ASP.net?](https://stackoverflow.com/questions/59093861/how-do-you-create-multi-level-ordered-lists-with-open-xml-in-asp-net) – Cindy Meister Dec 15 '19 at 06:12
  • @CindyMeister, in the context of Open XML and the Open XML SDK, saying that "numbering definitions _are_ styles" is not entirely accurate. _Styles_ are represented by `Style` instances contained in the `Styles` root element of the `StyleDefinitionsPart`. _Numbering definitions_ consist of numbering definition instances (`NumberingInstance`) and abstract numbering definitions (`AbstractNum`) contained in the `Numbering` root element of the `NumberingDefinitionsPart`. Open XML developers must understand that distinction. – Thomas Barnekow Dec 15 '19 at 12:53
  • @CindyMeister, unfortunately, I can't flag a question as a duplicate or even close it. In my answer below, I made a distinct point on how styles and numbering are both required and linked. This point was not included in my other answers, which describe other pertinent details required in a full answer to this question (which is likely why you linked one of them again in your comment). If that is not how it should be done, I'm happy to delete my answer. – Thomas Barnekow Dec 15 '19 at 13:04

1 Answers1

1

To use multi-level lists in Microsoft Word, you need to ensure that:

  1. you have the desired multi-level list set up correctly in your numbering definitions part (meaning your w:numbering element contains a w:num and corresponding w:abstractNum that specifies the different list levels);
  2. you have one style for each list level that references both the numbering ID specified by the w:num element and the desired list level; and
  3. your paragraphs reference the correct style for the list level.

Please have a look at my answers on how to create multi-level ordered lists with Open XML and display multi-level lists in Word documents using C# and the Open XML SDK for further details and explanations.

Thomas Barnekow
  • 2,059
  • 1
  • 12
  • 21