How to group items in InDesign using VB.Net/C#

First off, give up going the native route. There’s no way that I’ve found that you can convert an array to an InDesign.Objects object. Also, subclassing InDesign.Objects doesn’t appear to work either. What does ultimately work? JavaScript. Don’t worry, you can create JS on the fly and have InDesign execute it for you using the DoScript method of the Application object.

Below is an extension method of the InDesign.Document object that takes two or more InDesign.PageItem Id‘s. I haven’t found a way to cast specific objects (InDesign.Rectangle, InDesign.TextFrame, etc) to generic InDesign.PageItem so instead of writing tons of method signatures I’m just passing their internal integer IDs. The code is in VB.Net and should be pretty self-explanatory so someone should be able to convert it to C# very easily. Yes, I know the newlines aren’t necessary, but I like them. Why an Extension method? This snippet is one of many in my library and I find them easier to use if they’re extensions instead of sitting in a helper class.


    <Extension()>
    Public Function GroupObjects(ByVal indesignDocument As InDesign.Document, ByVal ParamArray objectIds() As Integer) As InDesign.Group
        'Sanity checks
        If indesignDocument Is Nothing Then Throw New ArgumentNullException("indesignDocument")
        If objectIds Is Nothing OrElse objectIds.Count < 2 Then Throw New ArgumentException("You must pass at least 2 object ids")

        'We'll assign a unique label to the group that we create in JavaScript so that we can find it in managed code later
        Dim GID = Guid.NewGuid().ToString()

        'Create the JavaScript
        Dim Buf As New StringBuilder()
        Buf.AppendLine("var items = new Array();")
        For Each ID In objectIds
            Buf.AppendFormat("items.push(app.activeWindow.activePage.pageItems.itemByID({0}));", ID)
            Buf.AppendLine()
        Next
        Buf.AppendLine("var g = app.activeWindow.activePage.groups.add(items);")
        Buf.AppendFormat("g.label='{0}';", GID)

        Dim IA = indesignDocument.Parent
        IA.DoScript(Buf.ToString(), InDesign.idScriptLanguage.idJavascript)

        'Loop through all document groups looking for the object with the label created above
        For Each G As InDesign.Group In indesignDocument.Groups
            If Not String.IsNullOrWhiteSpace(G.Label) AndAlso G.Label = GID Then Return G
        Next
        Return Nothing
    End Function

To call this Extension method, assuming that you have an InDesign.Document object called ID, a TextFrame called TF and a Rectangle called R:

ID.GroupObjects(TF.Id, R.Id)

Just to help people that are searching, one of the error messages that this will help resolve is:
Unable to cast object of type 'System.Object[]' to type 'InDesign.Objects'.