Search code examples
c#ms-wordoffice-interopword-contentcontrol

How to set ContentControl.Range to the current ContentControl I am working from?


I am not finding a way to set the ContentControl.Range.Text from where the C# is executing from (inside the content control). Perhaps I should be looking at it from a completely different perspective.

Currently I have a content control that produces a set of text with some text between [] square brackets and I want to select text and format the colour by setting the start and end of the range of characters between the []. I am stuck on trying to set the initial range to the contentcontrol I am currently using.

Most of what I have managed/found/patched together below.

object word;
Microsoft.Office.Interop.Word.Document _PWdDoc;

try
{
    word = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
    //If there is a running Word instance, it gets saved into the word variable
}
catch (Exception ex)
{
    //If there is no running instance, it creates a new one
    Type type = Type.GetTypeFromProgID("Word.Application");
    word = System.Activator.CreateInstance(type);
}

Microsoft.Office.Interop.Word.Application oWord = (Microsoft.Office.Interop.Word.Application) word;
_PWdDoc = oWord.ActiveDocument;

System.Collections.IEnumerator ContentX = _PWdDoc.ContentControls.GetEnumerator();
//Microsoft.Office.Interop.Word.ContentControl ContentX = Microsoft.Office.Interop.Word.ContentControls.Item[]; 
//Microsoft.Office.Interop.Word.Range rng = Microsoft.Office.Interop.Word.ContentControl.Range.Duplicate(ref ContentX);

//var rngX = Microsoft.Office.Interop.Word.ContentControl.Range(ContentX);
//Microsoft.Office.Interop.Word.ContentControl cc1 = ContentX;

Excuse the coding mess but it's all I can come up with with the minimal experience I have with this.

Now I have gotten the IEnumerator fo the Content Control(I think) I have no idea how to use it besides from what I have read, they say to iterate through the IEnumerables accessing each of them. That's not what I want to do. I want 1 content control. The current one that I am working in. I want to find it's range and assign it to a value. Then in that range's "text" I want to do some [fancy] highlighting.


Solution

  • Determining whether the current selection or a specific Range is in a content control and doing something with that content control is not a trivial matter. Most other Word objects will return something that they're "in"; content controls do not.

    So the approach I use is to

    • create a Range that reaches from the current selection (or a specific Range) back to the beginning of the document
    • count the number of content controls in that range
    • then check whether the current selection is in the same range as the last content control of the extended range.
    • if it is, then I know the selection is within a content control and I can access the content control.

    Here's some sample code. The snippet that calls the function I use to return the information:

            Word.Range rng = null;
            //Substitute a specific Range object if working with a Range, rather than a Selection
            Word.ContentControl cc = IsSelectionInCC(wdApp.Selection.Range);
    
            if ( cc != null)
            {
                rng = cc.Range;
                rng.HighlightColorIndex = Word.WdColorIndex.wdYellow;
            }
    

    The function:

        private Word.ContentControl IsSelectionInCC(Word.Range sel)
        {
            Word.Range rng = sel.Range;
            Word.Document doc = (Word.Document) rng.Parent;
            rng.Start = doc.Content.Start;
            int nrCC = rng.ContentControls.Count;
            Word.ContentControl cc = null;
            bool InCC = false;
    
            rng.Start = doc.Content.Start;
    
            if (nrCC > 0)
            {
                if (sel.InRange(doc.ContentControls[nrCC].Range))
                {
                    InCC = true; //Debug.Print ("Sel in cc")
                    cc = doc.ContentControls[nrCC];
                }
                else
                {
                    sel.MoveEnd(Word.WdUnits.wdCharacter, 1);
                    if (sel.Text == null)
                    {
                        //Debug.Print ("Sel at end of cc")
                        InCC = true;
                        cc = doc.ContentControls[nrCC];
                    }
                }
            }
            return cc;
        }