1

Here's my dilemma. I've been given a task to generate a specific section of an existing word document based on user input from a web front end. The back end of the system is being written in C# with the part that edits the word document using the Microsoft.Office.Interop.Word namespace.

Basically, they would select from a list of available instructions, each being of the type string, which will then be used to generate the instructions part of the document, with each separate instruction being another bullet in the list. This part works fine. My problem is, the instructions can contain the character \, which need to be replaced with an indent, or the equivalent of hitting TAB while in the bullet if you had the document opened in word. So far I'm able to get it to insert the bullets into the middle of the list just fine, it continues numbering them appropriately as expected. The kicker is I can't get it to indent them as needed.

I've tried pretty much all of the examples I was able to find here and on a few other sites to get this to work but with no success. The latest iteration is in the code below, which just indents the entire list as far as it can go.

var bookmark = "bookMarkName";
var docPath = @"c:\temp\Template.docx";
var app = new Application();
var doc = app.Documents.Open(docPath);
var range = doc.Bookmarks[bookmark].Range;
var listTemplate = range.ListFormat.ListTemplate;

range.ListFormat.ApplyListTemplate(listTemplate);

string[] bulletList = new string[] {
    @"Point A",
    @"\Point B",
    @"\Point C",
    @"\\Point D",
    @"Point E"
}

var count = bulletList.Length;

for (var i = 0; i < count; i++)
{
    var listLevel = 0;
    var currentItem = bulletList[i];
    var item = currentItem.Replace(@"\", "");

    if (i < count - 1)
        item = item + "\n";

    listLevel += currentItem.ToList().Where(x => x == '\\').Select(x => x).Count();

    for (var x = 0; x < listLevel; x++)
    {
        range.ListFormat.ListIndent();
    }

    range.InsertAfter(item);
}

doc.SaveAs(@"c:\temp\" + DateTime.Now.Ticks + ".docx");
doc.Close();

So the output of my code should be:

  • 1 Point A
    • 1.1 Point B
    • 1.2 Point C
      • 1.2.1 Point D
  • 2 Point E

This is the first time I've ever really had to work with the Office Interop libraries so I'm positive there's something I'm missing here. Any help would be greatly appreciated.

Dan S.
  • 173
  • 1
  • 14
  • Ummm, shouldn't you wait to replace the backslashes until after you've determined how many they are (which level the item belongs in)? – Cindy Meister Jun 26 '18 at 15:08
  • I suppose. I can't even figure out how to indent them as I'm inserting them. I wouldn't know where to begin with tracking down each of potentially dozens of list items after the fact. – Dan S. Jun 26 '18 at 15:57
  • Without background in how Word handles this, your question borders on being "too broad" - although I do sympathize. This part of Word is difficult, even in the UI. But if I try to answer this as it stands we won't get anywhere, I fear... – Cindy Meister Jun 26 '18 at 16:23
  • I recommend you start by opening Word as a user and investigating how to create such a list. You want the Home tab, Paragrph group, the Multilevel List button. Nothing in the gallery will match what you want, so choose "Define new multilevel list" from the menu. You'll see nine levels - select a level to change its appearance. For now, go to Number style for this level and look for the Bullet entries. Choose a bullet for each level you want to support. Experiment with the indents and other things until you get a list the way you want it to look and understand what you're dealing with. – Cindy Meister Jun 26 '18 at 16:24
  • @DanS. since the bullet indent amounts are governed by the amount of backslashes in each individual instruction, why not create styles for each level needed and then apply the styles to the text range based on the count of backslashes in each instruction? – joeschwa Jun 29 '18 at 05:05

2 Answers2

1

I don't have Office Interop on my computer, but you could try building the list with DocX, writing it to a file, then inserting that list into your document, from said file.

Something like this:

using System.Collections.Specialized;
...
...

DocX doc = DocX.Create("bullet-text.docx");

var firstItem = bulletList[0];
var firstItemLevel = firstItem.ToList().Count(c => c == '\\');
// Using full Namespace to avoid ambiguous reference error.
Xceed.Words.NET.List list = doc.AddList(firstItem.Replace("\\", ""), firstItemLevel, ListItemType.Numbered);

for (var i = 1; i < count; i++)
{
    var currentItem = bulletList[i];
    var item = currentItem.Replace(@"\", "");
    int listLevel = currentItem.ToList().Count(c => c == '\\')

    doc.AddListItem(list, item, listLevel, ListItemType.Numbered);

}

doc.InsertList(list);

doc.Save();

// Collapse the range to the end, as to not overwrite it. Unsure if you need this
range.Collapse(WdCollapseDirection.wdCollapseEnd);

// Insert into the selected range
range.InsertFile(Environment.CurrentDirectory + "\\bullet-text.docx");

References I canibalized:

Nested Bulleted lists in Novacode docx

How to embed file to word docx?

Collapse

InsertFile

Dan S.
  • 173
  • 1
  • 14
LolPython
  • 168
  • 1
  • 11
  • This worked! I'm sure a similar solution could be reached using only the interop libraries but this solved the issue. There's a small issue with getting it to continue the numbering but it fixed the actual problem of inserting and indenting list items into an existing document. – Dan S. Jul 03 '18 at 20:28
  • 1
    I had to make a few changes to your code to get it to work. 1) initialized the `list` variable outside of the loop so I could access it inside the loop, 2) moved the `doc.InsertList(list);` call to outside the loop to prevent duplicate items being generated, and 3) changed the `range.Collapse` call to include the full enum name, `range.Collapse(WdCollapseDirection.wdCollapseEnd)`. – Dan S. Jul 03 '18 at 20:34
  • Glad to hear it – LolPython Jul 03 '18 at 20:43
0

Please use this Code But Firstly Add DocX DLL

 using (var document = DocX.Create(@"docs\Lists.docx"))
    {
        var numberedList = document.AddList("First List Item.", 0, ListItemType.Numbered);
                //Add a numbered list starting at 2
        document.AddListItem(numberedList, "Second List Item.");
        document.AddListItem(numberedList, "Third list item.");
        document.AddListItem(numberedList, "First sub list item", 1);

        document.AddListItem(numberedList, "Nested item.", 2);
        document.AddListItem(numberedList, "Fourth nested item.");

        var bulletedList = document.AddList("First Bulleted Item.", 0, ListItemType.Bulleted);
        document.AddListItem(bulletedList, "Second bullet item");
        document.AddListItem(bulletedList, "Sub bullet item", 1);
        document.AddListItem(bulletedList, "Second sub bullet item", 2);
        document.AddListItem(bulletedList, "Third bullet item");

        document.InsertList(numberedList);
        document.InsertList(bulletedList);
        document.Save();
        Console.WriteLine("\tCreated: docs\\Lists.docx");
    }

Find Reference From Here

Hitesh Anshani
  • 1,499
  • 9
  • 19
  • This wouldn't solve my problem. I need to add a list to an existing document, not create a new one. I tried doing this with the DocX library. The `InsertList` method has the ability to insert a list at a specific character index in the document. This seems like it would solve the problem, but the library provides no way to actually get the index of anything, at least not that I've been able to find. – Dan S. Jun 29 '18 at 14:26
  • found this alternate https://stackoverflow.com/questions/11508286/bullet-points-in-word-with-c-sharp-interop – Hitesh Anshani Jun 29 '18 at 14:39
  • but atlast you can use this library to solve the issue with some different code i guess – Hitesh Anshani Jun 29 '18 at 14:40