Search code examples
c#ms-wordinteropvstooffice-interop

How to insert a cover page in MS Word at the beginning of the document?


I need to insert a cover page into a Word 2016 document. The building block is a cover page and has

InsertOptions = (int)WdDocPartInsertOptions.wdInsertPage; //= 2

So far so good.

But VSTO can only insert so:

buildingBlock.Insert(range);

It does insert in place of range.

The event Application.ActiveDocument.BuildingBlockInsert is not raised.

Using native insert cover page (tab insert --> cover page) does insert properly (and creates only one undo entry insert building block).

        // -----------------------------------------------------------------
        // try 1
        var range = Application.ActiveDocument.Range();
        range.Collapse(WdCollapseDirection.wdCollapseStart);
        buildingBlock.Insert(range);
        // result: inserting on the existing first page
        //           one undo entry 
        //           event BuildingBlockInsert has not been raised
        // -----------------------------------------------------------------
        // try 2
        //object start = 0;
        //object end = 0;
        //var range = Application.ActiveDocument.Range(ref start, ref end);
        //buildingBlock.Insert(range);
        // result: inserting on the existing first page
        //           one undo entry 
        //           event BuildingBlockInsert has not been raised
        // -----------------------------------------------------------------
        // try 3
        //var range = Application.ActiveDocument.Range();
        //range.InsertParagraphBefore();
        //var p = Application.ActiveDocument.Paragraphs[1];
        //buildingBlock.Insert(p.Range);
        // result: inserting on the existing first page
        //           two undo entries 
        //           event BuildingBlockInsert has not been raised
        // -----------------------------------------------------------------

A similar problem is described in Note of: https://learn.microsoft.com/en-us/office/vba/word/concepts/working-with-word/working-with-building-blocks#inserting-a-building-block-into-a-document

It seems VSTO ignores any insert options, and there is no way to parameterize insert option by inserting.

How can VSTO insert a building block in a new first page as a Word native action?

I'm using VS 2017 Word 2016 Add-In, .Net Framework 4.6.1.


Solution

  • Summary:

    1. VSTO just "imitate" native Word building block inserting and not all features (InsertOptions) and functionalities (document event BuildingBlockInsert) are bound.
    2. Combining native Word Ui user expirience (add/replace, remove cover page) and your custom VSTO Add-In (add/replace cover page) is only conditionally possible.

    My current code:

    private static Microsoft.Office.Interop.Word.Application Application => Globals.ThisAddIn.Application;
    
    private void InsertCoverPage(BuildingBlock buildingBlock)
    {
        // validate not null
        if(buildingBlock == null) throw new ArgumentNullException(nameof(buildingBlock));
    
        // validate is a cover page
        if (buildingBlock.Type.Index != (int)WdBuildingBlockTypes.wdTypeCoverPage &&
            buildingBlock.Type.Index != (int)WdBuildingBlockTypes.wdTypeCustomCoverPage)
        {
            throw new ArgumentNullException(nameof(buildingBlock));
        }
    
        // validate insert option
        if (buildingBlock.InsertOptions != (int) WdDocPartInsertOptions.wdInsertPage) 
        {
            throw new Exception(
                "building block as a cover page must been inserted in a new page at the beginning of document");
        }
    
        Application.ScreenUpdating = false;
    
        Range range = GetCurrentCoverPageRange() ?? Application.ActiveDocument.Range(0, 0);// search a first existing cover page range
    
        range.InsertBreak(WdBreakType.wdPageBreak); // case existing cover page: replace by page break 
        // range.Start = 0; // = 0
        range.End = 0; // reset only end position
        buildingBlock.Insert(range, true);
    
        Marshal.ReleaseComObject(range);
    
        Application.ScreenUpdating = true;
    }
    
    private Range GetCurrentCoverPageRange()
    {
        Range result = null;
    
        // Word insert natively a cover page with 2 paragraphs - so we need found these first 2 consecutive paragraphs marked as a cover page
        for (int i = 1; i < Application.ActiveDocument.Paragraphs.Count + 1; i++)
        {
            var paragraph = Application.ActiveDocument.Paragraphs[i];
            var isCoverPage = (bool)paragraph.Range.Information[WdInformation.wdInCoverPage];
            if (isCoverPage)
            {
                if (result == null)
                {
                    result = paragraph.Range;
                }
                else
                {
                    result.End = paragraph.Range.End;
                }
            }
            else
            {
                if (result != null)
                {
                    break;
                }
            }
        }
    
        return result;
    }