问题
I'm trying to insert text before a list. I have the Microsoft.Office.Interop.Word.Range
of the list, and get the previous Range before the list. I then try to add my paragraph text to the previous range, however, the paragraph is added as the first item in the list instead of before the list.
// rangeObj is the Range object for the list
var previousRange = rangeObj.Previous(MSWord.WdUnits.wdCharacter, 1);
Paragraph paragraph;
if (previousRange == null)
{
var rangeCopy = rangeObj.Duplicate;
rangeCopy.InsertParagraphBefore();
paragraph = rangeCopy.Paragraphs[1];
}
else
{
paragraph = previousRange.Paragraphs[1];
}
Range range = paragraph.Range;
range.Text = String.Format("{0} {1}", "My list", range.Text);
E.g. Before:
- Item 1
- Item 2
After (What I want):
My list
- Item 1
- Item 2
After (What I'm currently getting):
- My list
- Item 1
- Item 2
Edit: Per Lasse's answer and my comment, I'm getting everything to work except for the following edge case. Note: The 2nd list is not a sub list of the first one and there's no empty lines in-between each list.
if (previousRange.ListParagraphs.Count > 0)
Before:
- Item 1
Item 2
- Item 3
- Item 4
After (what I want):
- Item 1
Item 2
Another list:
- Item 3
- Item 4
回答1:
In this code:
else
{
paragraph = previousRange.Paragraphs[1];
}
.. you are risking overwriting anything before the list (including empty lines with only \r
in it), and when I run it on a sample, it makes good sense that things gets overwritten and occur weird in the end.
In this code:
if (previousRange == null)
{
var rangeCopy = rangeObj.Duplicate;
rangeCopy.InsertParagraphBefore();
paragraph = rangeCopy.Paragraphs[1];
}
.. you insert a new paragraph before the list (which is fine - even though, I cannot see why it would be necessary to clone the range, as the range automatically expands to include the newly inserted paragraph) and then stores the range of the new paragraph in your local variable paragraph
. At this point, the content of paragraph = '\r'
- (this is seen if you step through your application with a debugger while keeping word visible during the debugging phase). So, at this point the cursor is positioned just before the list, which is where you want it to be - but then you do the following:
Range range = paragraph.Range;
range.Text = "My paragraph";
... meaning that instead of pre-pending text to the paragraph, you simply overwrite everything including the \r
, which causes Word to insert the text in the list instead of before it.
To bypass this, I have made an alternative implementation that seems to work. It is based on your idea of using the range before the list to insert text. I have added comments for most of the lines, so it should be straight forward to follow what is going on :)
using System;
using System.Linq;
using Microsoft.Office.Interop.Word;
using Application = Microsoft.Office.Interop.Word.Application;
namespace WordDocStats
{
internal class Program
{
private static void Main()
{
var wordApplication = new Application() { Visible = true };
// Open document A
var documentA = wordApplication.Documents.Open(@"C:\Users\MyUser\Documents\documentA.docx", Visible: true);
// This inserts text in front of each list found in the document
const string myText = "My Text Before The List";
foreach (List list in documentA.Lists)
{
// Range of the current list
var listRange = list.Range;
// Range of character before the list
var prevRange = listRange.Previous(WdUnits.wdCharacter);
// If null, the list might be located in the very beginning of the doc
if (prevRange == null)
{
// Insert new paragraph
listRange.InsertParagraphBefore();
// Insert the text
listRange.InsertBefore(myText);
}
else
{
if (prevRange.Text.Any())
{
// Dont't append the list text to any lines that might already be just before the list
// Instead, make sure the text gets its own line
prevRange.InsertBefore("\r\n" + myText);
}
else
{
// Insert the list text
prevRange.InsertBefore(myText);
}
}
}
// Save, quit, dones
Console.WriteLine("Dones");
Console.ReadLine();
documentA.Save();
wordApplication.Quit();
}
}
}
In short, the code inserts a string before each list in the given document. If there is already text on the line before the list, the implementation makes sure to insert the list description text before the list and after the text that was already on the line before the list.
Hope this helps :)
--- UPDATE to answer to edited question:
A way to accomplish what you are asking here in the second round is doing something like:
...
// The paragraph before the current list is also a list -> so in order to insert text, we must do "some magic"
else if(prevRange.ListParagraphs.Count > 0)
{
// First, insert a new line -> this causes a new item to be inserted into the above list
prevRange.InsertAfter("\r");
// Modify current range to be on the line of the new list item
prevRange.Start = prevRange.Start + 1;
prevRange.End = prevRange.Start;
// Convert the list item line into a paragraph by removing its numbers
prevRange.ListFormat.RemoveNumbers();
// Insert the text
prevRange.InsertBefore(myText);
}
...
Just add that code to the if-else
block inside the foreach
loop of the sample code I have provided above and you should be good to go :) I have tested it on my machine with MS Word 2013, and it seems to work.
来源:https://stackoverflow.com/questions/13311310/insert-text-before-a-list-using-word-interop