I hope you can help me with my problem.
I want to automatically generate a Word checklist with a C# program.
But I can't get it to put the text behind the checkbox. The text always lands in a new line under the checkbox.
How can I solve this problem?
You know some other functions?
public void createChecklist()
{
Application app = new Application();
app.Visible = true;
Document doc = app.Documents.Add();
Paragraph para = doc.Paragraphs.Add();
ContentControl checkbox = para.Range.ContentControls.Add(WdContentControlType.wdContentControlCheckBox);
para.Range.InsertAfter("sdjsakd");
doc.SaveAs2("C:\\tmp\\checklist.docx");
app.Quit();
}
The reason for the behavior is because the "target" for the text is the range of the entire paragraph. So when something is inserted after, it's inserted after the paragraph.
The key to this is to bring the range back to within the paragraph - to not include the paragraph mark. (The paragraph mark is not visible in the screen shot because the display of non-printing characters is suppressed. Click the "backwards P" in the Home tab of the Ribbon and the paragraph mark should be visible.)
There are various ways to approach this; Range.MoveEnd
is used quite often (below).
Note: It's dangerous when using COM "interop" to not clean up the objects. This could quickly lead to "orphaned" instances of the application staying in memory. I've added that to the code sample since the code in the question quits the Word application.
public void createChecklist()
{
Application app = new Application();
app.Visible = true;
Document doc = app.Documents.Add();
Paragraph para = doc.Paragraphs.Add();
Range rng = para.Range;
ContentControl checkbox = rng.ContentControls.Add(WdContentControlType.wdContentControlCheckBox);
rng.MoveEnd(WdUnits.wdCharacter, -1);
rng.InsertAfter(" sdjsakd");
doc.SaveAs2("C:\\tmp\\checklist.docx");
//Release the COM objects and clean up
checkbox = null;
rng = null;
para = null;
doc = null;
app.Quit();
app = null;
GC.Collect(); GC.AwaitPendingFinalizers();
GC.Collect(); GC.AwaitPendingFinalizers();
}
Added note to clarify question of why run the garbage collection twice:
This information comes from Andrew Whitechapel's ".Net Development for Microsoft Office", Chapter 2, the extract of which is no longer available on MSDN, so quoted here:
Note that we're repeating the calls to Collect
and
WaitForPendingFinalizers
This is because the memory for the [Office
application reference] might have survived the first pass, although it
will then have been marked for collection on the next pass. So we will
make a second pass to clean up anything that survived the first pass
but was otherwise available for collection.