Copy a sheet from one project to another

In response to my post “Transferring just one View Template from Project to Project“, Mike asks:

How would you implement this to copy sheets?

To start, it is not possible to copy viewports with the API. This is not too much of a surprise, as the Revit UI does not allow duplicating sheets and does not allow copying viewports. Also, it is not possible to copy a sheet that has viewports on it.

However, it is possible to use the API to copy the sheet, titleblock, and view-specific elements on the sheet if we use this procedure:

  1. Temporarily delete the viewports from the sheet (this is done in a transaction that be rolled back at the end so that the viewports are not actually deleted)
  2. Copy the sheet to the new project
  3. Copy the view-specific elements (excluding the viewports) from the source sheet view to the destination sheet view

The sneaky part of this is realizing that that while a single document can have only one transaction open at any given time, we can have one transaction in each document open at the same time.

public void CopySheet()
{
    Document doc = this.ActiveUIDocument.Document;

    ViewSheet activeViewSheet = doc.ActiveView as ViewSheet;
    if (activeViewSheet == null)
    {
        TaskDialog.Show("Error", "Active view must be a sheet.");
        return;
    }

    Application app = this.Application;
    Document otherDoc = app.Documents.Cast<Document>().Where(d => d.Title != doc.Title).FirstOrDefault();
    if (otherDoc == null)
    {
        TaskDialog.Show("Error", "There must be a 2nd document open.");
        return;
    }

    // put the sheet in the source document into the copyIds collection
       ICollection<ElementId> copyIds = new Collection<ElementId>();
    copyIds.Add(activeViewSheet.Id);    

    // put view-specific elements on the sheet in the copyIdsViewSpecific collection
    ICollection<ElementId> copyIdsViewSpecific = new Collection<ElementId>();
    foreach (Element e in new FilteredElementCollector(doc).OwnedByView(doc.ActiveView.Id))
    {
        // do not put viewports into this collection because they cannot be copied
        if (!(e is Viewport))
            copyIdsViewSpecific.Add(e.Id);    
    }

    // Create a transaction in the source document to delete the viewports.
    // This transaction will be rolled-back so it won't cause any permanent change in the document
    // but it will enable copying of the sheet while it is in a state with no viewports
    using (Transaction t = new Transaction(doc,"Delete Viewports"))
    {
        t.Start();

        IList<Viewport> viewports = new FilteredElementCollector(doc).OfClass(typeof(Viewport)).Cast<Viewport>()
            .Where(q => q.SheetId == activeViewSheet.Id).ToList();

        foreach (Viewport vp in viewports)
        {
            doc.Delete(vp.Id);
        }

        using (Transaction tOther = new Transaction(otherDoc, "Copy View Template"))
        {
            tOther.Start();
            // copy the sheet using the CopyElements overload that accepts source and destination documents
            // get the newly created sheet in the target document - it will be the first (and only) element returned by ElementTransformUtils.CopyElements
            ViewSheet newSheet = otherDoc.GetElement(ElementTransformUtils.CopyElements(doc, copyIds, otherDoc, Transform.Identity, new CopyPasteOptions()).First()) as ViewSheet;

            // copy the view-specific elements using the CopyElements overload that accepts source and destination views
            ElementTransformUtils.CopyElements(activeViewSheet, copyIdsViewSpecific, newSheet, Transform.Identity, new CopyPasteOptions());

            tOther.Commit();
        }

        // rollback the transaction to "undo" the deletion of the viewports
        t.RollBack();
    }
}
Advertisements

9 thoughts on “Copy a sheet from one project to another

  1. Thanks Harry. So you don’t think there’s anyway to get drafting view viewports to work? The “Insert Views from File” can copy over drafting views on the sheet and was hoping I could make that work through here as well. I’m thinking that the views need to be collected and copied over first, their placement on the sheet recorded and then recreated in the new document.

  2. Hi Harry, I tried translating your code to python so I could use it with the Revit Python Shell.
    It works fine up until the last CopyElements, I get a copy of the sheet with the correct parameters and no titleblock in the other document but the line:

    ElementTransformUtils.CopyElements(activeViewSheet, copyIdsViewSpecific, newSheet, Transform.Identity, CopyPasteOptions())

    gives me an error:
    Exception: Some of the elements cannot be copied, because they belong to a different document.
    Parameter name: elementsToCopy

    for copyIdsViewSpecific I have:

    copyIdsViewSpecific = List[ElementId]()
    for e in FilteredElementCollector(doc).OwnedByView(doc.ActiveView.Id):
    if (not(e is Viewport)):
    copyIdsViewSpecific.Add(e.Id)

    Is this a python related issue?
    or should I be using this function instead: CopyElements(sourceDocument: Document, elementsToCopy: ICollection[ElementId], destinationDocument: Document, transform: Transform, options: CopyPasteOptions) -> ICollection[ElementId]
    but then how would I get it to copy the elements on the new sheet?

  3. You should continue to use the CopyElements override that uses two views. To debug this, you could investigate the elements whose IDs are in copyIdsViewSpecific to see if any of them seem incorrect.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s