1
votes

I've been scouring the interwebs for documentation leading me to be able to create lists. In doing so, I've not really been able to find any documentation that will allow me to create `lists within lists.

I've tried using the built-in macro recorder, but for whatever reason, it behaves differently when recording vs. when not recording (e.g. when I create a list item, and hit enter + tab, it doesn't create a sub list).

I've found "The Wordmeister's" MSDN post which helped me get to making a list, but lists within lists doesn't work so well for me.

            Word.Paragraph p2 = doc.Paragraphs.Add();
            Word.Range p2rng = p2.Range;
            object oTrue = true;
            object oFalse = false;
            object oListName = "TreeList";

            Word.ListTemplate lstTemp = doc.ListTemplates.Add(ref oTrue, ref oListName);
            int l;

            p2rng.ParagraphFormat.TabIndent(1);
            p2rng.Text = "Rates:\r\nLevel 1\rLevel 1.1\rLevel 1.2\rLevel 2\rLevel 2.1\rLevel 2.1.1";

            l = 1;
            lstTemp.ListLevels[l].NumberFormat = "%" + l.ToString() + ".";
            lstTemp.ListLevels[l].NumberStyle = Word.WdListNumberStyle.wdListNumberStyleArabic;
            lstTemp.ListLevels[l].NumberPosition = wordApp.CentimetersToPoints(0.5f * (l - 1));
            lstTemp.ListLevels[l].TextPosition = wordApp.CentimetersToPoints(0.5f * l);
            l = 2;
            lstTemp.ListLevels[l].NumberFormat = "%" + (l - 1).ToString() + ".%" + l.ToString() + ".";
            lstTemp.ListLevels[l].NumberStyle = Word.WdListNumberStyle.wdListNumberStyleArabic;
            lstTemp.ListLevels[l].NumberPosition = wordApp.CentimetersToPoints(0.5f * (l - 1));
            lstTemp.ListLevels[l].TextPosition = wordApp.CentimetersToPoints(0.5f * l);
            l = 3;
            lstTemp.ListLevels[l].NumberFormat = "%" + (l - 2).ToString() + "%" + (l - 1).ToString() + ".%" + l.ToString() + ".";
            lstTemp.ListLevels[l].NumberStyle = Word.WdListNumberStyle.wdListNumberStyleArabic;
            lstTemp.ListLevels[l].NumberPosition = wordApp.CentimetersToPoints(0.5f * (l - 1));
            lstTemp.ListLevels[l].TextPosition = wordApp.CentimetersToPoints(0.5f * l);
            object oListApplyTo = Word.WdListApplyTo.wdListApplyToWholeList;
            object oListBehavior = Word.WdDefaultListBehavior.wdWord10ListBehavior;

            p2rng.ListFormat.ApplyListTemplate(lstTemp, ref oFalse, ref oListApplyTo, ref oListBehavior);

All credit to Cindy Meister for this code, it is only slightly modified to work for my use case.

The above results in the following:

enter image description here

Basically, how do you create multi level lists (like the following image) with lists within lists?

enter image description here

2
@Jaberwocky the Interop API is the same as that used by VBA. You can record a macro while creating a nested list and convert the VBA code to C#. You most definitedly don't need to hand-code numbers and bullets though. Word itself provides that for lists. You don't need (actually shouldn't) to use \r\n to generate lines in a paragraph. None of those characters will result in the soft-newline you want. - Panagiotis Kanavos
@Jaberwocky as for the macro recorder not working the same, it's because what you do is not what you do - when you click tab you don' create a second level list, you insert a Tab. Word can "autocorrect" that and apply a List 2 style instead of adding a tab to the list. If you simply applied the correct style to the second list item, you'd see that the macro recorder's code and your own actions would match - Panagiotis Kanavos
@Jaberwocky you should probably learn how Word works first, how formatting, lists, numbering etc work. Just like HTML, you can try to align and format a page with tabs, spaces and wonder why it doesn't work. Or you can read about divs, css etc and generate a nicely formatted page. - Panagiotis Kanavos

2 Answers

0
votes

It's not really possible to create a "list within a list" in Word.

What you can do is put static text in the list level, in front of the dynamic number. This is the same idea as using "Chapter" or "Section" in front of the level's number, except in this case it should be a bullet symbol.

The place to define this, based on the code sample in the question, is:

lstTemp.ListLevels[l].NumberFormat = "%" + l.ToString() + ".";

As part of the NumberFormat string, in other words. For symobls this will require a conversion from unicode hex or decimal to the String data type. For example, for a solid, round bullet and an outline, round bullet for levels 1 and 2, respectively (hard-coding the list level for purposes of clarity):

char Symbol1 = (char)9679;
char Symbol2 = (char)9675;
lstTemp.ListLevels[1].NumberFormat = Symbol1.ToString() + "\t%" + l.ToString() + ".";
lstTemp.ListLevels[2].NumberFormat = Symbol2.ToString() + "\t%" + 2.ToString() + ".";
-1
votes

Lets try providing an answer that doesn't get deleted.

The updated list within lists example provided by @Jaberwocky can be achieved using the technique I explained in a previous post.

MS-Word: Cross reference to custom reference type

To apply the above to the specific instance required by @Jaberwock we need to amend the number formats of the list templates to which styles are linked. I'll use Word to set up the styles and required multilevel list and then include a short VBA macro which shows how to amend the list number format.

In line with the link above we first need to create our styles. The emulate the list within list example above we need to define two styles. I've defined 'ListWithinList 1' and 'ListWithinList 2'.

The key settings for these two styles are to set the outline level as 1 and 2 respectively, and to set appropriate tab stops. I've used tabs at 1,2,3 and 4 cm. Add some text to a word document and apply the styles. I've included the navigation pane in the picture below so that we can see the indentation due to the outline level of the styles

enter image description here

The next step is to define the multilevel list and link each level to the relevant style

Settings for outline level 1

enter image description here

settings for outline level 2

enter image description here

Our text now looks like this

enter image description here

I've used Word up to this point to avoid the tediousness of setting up styles and list templates programatically.

Let's now modify the format of the list numbering using a snippet of VBA.

Option Explicit

Public Sub AddTextToListNumber()

Dim my_prefix(1 To 2)                   As String
Dim my_index                            As Long

    my_prefix(1) = ChrW(&H25AA) & vbTab ' small black square
    my_prefix(2) = ChrW(&H25AB) & vbTab ' small white square

    For my_index = 1 To 2

        With ActiveDocument.Styles("ListWithinList " & CStr(my_index)).ListTemplate.ListLevels(my_index)
            .numberformat = my_prefix(my_index) & .numberformat
        End With
    Next

End Sub  

If we run the code above then the text in our document becomes

enter image description here

Which looks a bit ugly because of the 1cm tab stops.

If there is anything that isn't clear above please add a comment and if possible I'll update the answer.

NOTE: We didn't need the VBA code to complete setting up the list formats as we could have used appropriate Alt+XXXX keyboard sequences to insert the characters in the number format box of the multilevel list dialog box.