API: Copying drafting views between documents

API: Copying drafting views between documents

noamgatCXBC7
Participant Participant
1,794 Views
14 Replies
Message 1 of 15

API: Copying drafting views between documents

noamgatCXBC7
Participant
Participant

Hello,

We are trying to copy drafting views between documents, and are having trouble.

We found two knowledge bases related to this:

 

One: "Insert a Drafting View from Another Project" - https://help.autodesk.com/view/RVT/2019/ENU/?guid=GUID-8DC49C5E-E0B0-41A1-8933-B62755A2FA07

This is exactly what we want to do, but we cannot find the API calls to do this in C#.

 

Two: DuplicateViewUtils from https://github.com/jeremytammik/RevitSdkSamples/blob/68771b6636ba72ec61dde611ece40209a28442bf/SDK/Sa...

This sounds like exactly what we want to do, however its not working in practice. We get an error "Cannot paste view specific elements from different views". Indeed our drafting views have many view-specific elements (such as dimensions) which is probably the reason for this failure. This is also discussed in other places - https://forums.autodesk.com/t5/revit-architecture-forum/copy-paste-groups-from-one-view-to-another/t...

 

Is there a way to get DuplicateViewUtils to work with drafting views with view specific elements? Is there an API call that is equivalent to the "Insert a Drafting View from Another Project" help page?

0 Likes
1,795 Views
14 Replies
Replies (14)
Message 2 of 15

sragan
Collaborator
Collaborator

FWIW:  I can highlight the titles of views in the project browser, and copy them to a new project by just hitting ctrl-C and ctrl-V. 

 

So maybe is there some way to use the generic windows copy and paste command to do this?

Message 3 of 15

noamgatCXBC7
Participant
Participant

 

We are able to copy / paste from the UI as well, but this can't be automated in a revit plugin as far as I know

0 Likes
Message 4 of 15

RPTHOMAS108
Mentor
Mentor

 

If the objects are view specific (which is the case for all objects on drafting views) then use the overloads that copy between views.

 

Use CopyPasteOptions.SetDuplicateTypeNamesHandler to avoid the duplicate names issue. 

 

In the below you may be curious as to the benefits of copying the drafting view rather than just creating a new one to copy objects into. If you copy the view then you likely don't have to replicate the view settings such as scale, category visibility and filters. In fact if you think about it then isn't that a good way in itself of replicating some of the features of transfer project standards (it brings in what it needs)?

 

Private Function Obj_221208b(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result
        Dim UIApp As UIApplication = commandData.Application
        Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else
        Dim IntDoc As Document = UIDoc.Document

        Dim Path As String = "c:\temp\rt_draftingviewsource.rvt"
        Const DVName As String = "DraftingViewX"
        Dim OtherDoc As Document = commandData.Application.Application.OpenDocumentFile(Path)

        Dim FEC As New FilteredElementCollector(OtherDoc)
        Dim DV As Element = FEC.OfClass(GetType(ViewDrafting)).Where(Function(k) k.Name = DVName).FirstOrDefault


        Using tx As New Transaction(IntDoc, "Copy")
            If tx.Start = TransactionStatus.Started Then
                Dim Ids As ICollection(Of ElementId) =
                    ElementTransformUtils.CopyElements(OtherDoc, {DV.Id}.ToList, IntDoc, Transform.Identity, New CopyPasteOptions)

                Dim DestView As Element = IntDoc.GetElement(Ids(0))
                Dim FEC0 As New FilteredElementCollector(OtherDoc, DV.Id)
                Dim ViewItms As List(Of ElementId) = FEC0.WhereElementIsNotElementType.ToElementIds

                ElementTransformUtils.CopyElements(DV, ViewItms, DestView, Transform.Identity, New CopyPasteOptions)

                tx.Commit()
            End If
        End Using
        OtherDoc.Close(False)

        Return Result.Succeeded

    End Function

 

 

 

 

 

 

 

 

Message 5 of 15

noamgatCXBC7
Participant
Participant

This is what the API sample code does.

We investigated further and it looks like only some elements are failing - callouts that refer to other views.

Is there any way to handle this case?

 

 

Message 6 of 15

RPTHOMAS108
Mentor
Mentor

Yeah I think the issue there is that you would have to bring in the views they refer to first but even that may not work. What happens in the UI equivalent (copy paste)? From testing it prompts you to select a view to associate with it after after pasting.

 

i.e. if you are copying between projects then what would the call out refer to if the referenced view isn't already in the destination.

 

I expect all you can do is filter them out:

 

Dim Ids As ICollection(Of ElementId) =
                    ElementTransformUtils.CopyElements(OtherDoc, {DV.Id}.ToList, IntDoc, Transform.Identity, New CopyPasteOptions)
Dim DestView As Element = IntDoc.GetElement(Ids(0))
Dim FEC0 As New FilteredElementCollector(OtherDoc, DV.Id)
Dim ECF As New ElementCategoryFilter(BuiltInCategory.OST_Viewers, True)
Dim ViewItms As List(Of ElementId) = FEC0.WhereElementIsNotElementType.WherePasses(ECF).ToElementIds
ElementTransformUtils.CopyElements(DV, ViewItms, DestView, Transform.Identity, New CopyPasteOptions)

 

You can replicate the call outs via

ViewSection.CreateReferenceCallout
ViewSection.CreateReferenceSection

 

You would have to have a replacement view in the destination to reference. The awkward part would be getting the points that define the outline. I don't see an easy way of doing that, it is relatively easy for a shaped callout because then you have a sketch. IExportContext2d could have been the way but it doesn't support drafting views oddly.

 

Message 7 of 15

noamgatCXBC7
Participant
Participant

 

Thanks! That is a very interesting direction to explore. I was hoping to find a way to avoid the outline recreation. I was hoping that if a view with the same name exists in the target document, the callout could be copied. But it does not seem to be that way.

0 Likes
Message 8 of 15

matthew.joseph.frank
Participant
Participant

@noamgatCXBC7 - did you get anywhere with this?


We are working on copying ViewSections with referenced views from one document to another.

 

We have taken the approach of replicating the callouts, but we've run into the following issues:
Callout head placed in default position
Cannot adjust callout head position
Reference sections do not have a CropShape when using the ViewSection.CreateReferenceSection method. Therefore, when we attempt to replicate the reference section to another document, it fails to replicate due to lack of CropShape (line 30 of code snip below).

 

We have attempted to use ViewCropRegionShapeManager.SetCropShape() to define the crop shape after creating the reference section with no luck passing in the same Curveloop from the original section, nor when passing the original curves of the section into a new Curveloop (We did not go as granular as defining each point for StartPoint/EndPoint of each curve to create a Curveloop that way). 

 

Below is a code snip (we error at line 30 - list is empty) :

        {
            try
            {
                // Get Family and Type Parameter
                Parameter sectionFamilyAndType = section.LookupParameter("Family and Type");
                ElementId sectionFamilyAndTypeId = sectionFamilyAndType.AsElementId();
                var sectionViewFamilyType = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _schaeferDetailsDoc : _doc).GetElement(sectionFamilyAndTypeId);

                // Get Section Tag Parameter
                Parameter sectionTagParameter = sectionViewFamilyType.LookupParameter("Section Tag");
                ElementId sectionTagId = sectionTagParameter.AsElementId();
                var sectionTag = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _schaeferDetailsDoc : _doc).GetElement(sectionTagId);

                // Get Section Head Parameter
                Parameter sectionHeadParameter = sectionTag.LookupParameter("Section Head");
                ElementId sectionHeadId = sectionHeadParameter.AsElementId();
                FamilySymbol sectionHead = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _schaeferDetailsDoc : _doc).GetElement(sectionHeadId) as FamilySymbol;

                // Get Section Tail Parameter
                Parameter sectionTailParameter = sectionTag.LookupParameter("Section Tail");
                ElementId sectionTailId = sectionTailParameter.AsElementId();
                FamilySymbol sectionTail = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _schaeferDetailsDoc : _doc).GetElement(sectionTailId) as FamilySymbol;

                // Get Broken Section Display Style Parameter
                Parameter brokenSectionDisplayStyleParameter = sectionTag.LookupParameter("Broken Section Display Style");
                string brokenSectionDisplayStyleValue = brokenSectionDisplayStyleParameter.AsValueString();

                // Get crop shape of callout
                ViewCropRegionShapeManager refSectionCRSM = View.GetCropRegionShapeManagerForReferenceCallout(_direction == ReferenceDirection.SchaeferDetailsToProject ? _schaeferDetailsDoc : _doc, section.Id);
                IList<CurveLoop> refSectionCropShapeList = refSectionCRSM.GetCropShape();
                CurveLoop refSectionCropShape = refSectionCropShapeList[0];
                CurveLoopIterator curveLoopIterator = refSectionCropShape.GetCurveLoopIterator();
                Curve refSectionCropShapeCurve = curveLoopIterator.Current;
                XYZ startPoint = refSectionCropShapeCurve.GetEndPoint(0);
                XYZ endPoint = refSectionCropShapeCurve.GetEndPoint(1);
                bool continueIterating = curveLoopIterator.MoveNext();

                //Get XYZ points of callout
                XYZ max = new XYZ(startPoint.X, startPoint.Y, 0);
                XYZ min = new XYZ(startPoint.X, startPoint.Y, 0);

                while (continueIterating)
                {
                    refSectionCropShapeCurve = curveLoopIterator.Current;
                    startPoint = refSectionCropShapeCurve.GetEndPoint(0);
                    endPoint = refSectionCropShapeCurve.GetEndPoint(1);

                    if (startPoint.X > max.X)
                    {
                        max = new XYZ(startPoint.X, max.Y, 0);
                    }
                    else if (startPoint.X < min.X)
                    {
                        min = new XYZ(startPoint.X, min.Y, 0);
                    }

                    if (startPoint.Y > max.Y)
                    {
                        max = new XYZ(max.X, startPoint.Y, 0);
                    }
                    else if (startPoint.Y < min.Y)
                    {
                        min = new XYZ(min.X, startPoint.Y, 0);
                    }

                    continueIterating = curveLoopIterator.MoveNext();
                }

                using (Transaction t4 = new Transaction(_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc, "Duplicate view detailing"))
                {
                    t4.Start();

                    // have to get all the callouts already in the detail before creating the new one
                    ICollection<ElementId> existingRefSections = (_direction == ReferenceDirection.SchaeferDetailsToProject ? detail.ProjectDraftingView : detail.SchaeferDetailsDraftingView).GetReferenceSections();

                    // because this stupid method doesn't tell you the id of the element it creates... how dumb?
                    if (_direction == ReferenceDirection.SchaeferDetailsToProject) ViewSection.CreateReferenceSection(_doc, detail.ProjectDraftingView.Id, relatedDetail.ProjectDraftingView.Id, min, max);
                    else if (_direction == ReferenceDirection.WorkingModelToSchaeferDetails) ViewSection.CreateReferenceSection(_schaeferDetailsDoc, detail.SchaeferDetailsDraftingView.Id, relatedDetail.SchaeferDetailsDraftingView.Id, min, max);

                    // so then have to get the new element id like this... obviously, i'm annoyed by this right now...
                    // there should only be one additional id
                    IEnumerable<ElementId> newRefSectionIdsToDoc = (_direction == ReferenceDirection.SchaeferDetailsToProject ? detail.ProjectDraftingView : detail.SchaeferDetailsDraftingView).GetReferenceSections().Except(existingRefSections);

                    ElementId refSectionIdToDoc = null;

                    foreach (ElementId _refSectionIdToDoc in newRefSectionIdsToDoc)
                    {
                        ElementId refViewId = ReferenceableViewUtils.GetReferencedViewId(_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc, _refSectionIdToDoc);

                        if (refViewId == (_direction == ReferenceDirection.SchaeferDetailsToProject ? relatedDetail.ProjectDraftingView.Id : relatedDetail.SchaeferDetailsDraftingView.Id))
                        {
                            refSectionIdToDoc = _refSectionIdToDoc;
                            break;
                        }
                    }

                    Element refSectionToDoc = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc).GetElement(refSectionIdToDoc);

                    // Get Family and Type
                    Parameter sectionFamilyAndTypeToDoc = refSectionToDoc.LookupParameter("Family and Type");
                    ElementId sectionFamilyAndTypeToDocId = sectionFamilyAndTypeToDoc.AsElementId();
                    var sectionViewFamilyTypeToDoc = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc).GetElement(sectionFamilyAndTypeToDocId);

                    // Get Section Tag
                    Parameter sectionTagToDocParameter = sectionViewFamilyTypeToDoc.LookupParameter("Section Tag");
                    ElementId sectionTagToDocId = sectionTagToDocParameter.AsElementId();
                    var sectionTagToDoc = (_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc).GetElement(sectionTagToDocId);

                    // Set Section Head
                    Parameter sectionHeadToDocParameter = sectionTagToDoc.LookupParameter("Section Head");
                    ICollection<Element> sectionHeads = new FilteredElementCollector(_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc).OfCategory(BuiltInCategory.OST_SectionHeads).ToElements();
                    ElementId sectionHeadToDocId = null;
                    foreach (Element elem in sectionHeads)
                    {
                        FamilySymbol secHead = elem as FamilySymbol;
                        string sectionHeadName = sectionHead.Name;
                        if (char.IsDigit(sectionHeadName[sectionHeadName.Length - 1]))
                        {
                            sectionHeadName = sectionHeadName.Remove(sectionHeadName.Length - 1);
                        }

                        if (secHead.Name.Contains(sectionHeadName.Trim()))
                        {
                            sectionHeadToDocId = secHead.Id;
                            break;
                        }
                    }
                    sectionHeadToDocParameter.Set(sectionHeadToDocId);

                    // Set Section Tail
                    Parameter sectionTailToDocParameter = sectionTagToDoc.LookupParameter("Section Tail");
                    ICollection<Element> sectionTails = new FilteredElementCollector(_direction == ReferenceDirection.SchaeferDetailsToProject ? _doc : _schaeferDetailsDoc).OfCategory(BuiltInCategory.OST_SectionHeads).ToElements();
                    ElementId sectionTailToDocId = null;
                    foreach (Element elem in sectionTails)
                    {
                        FamilySymbol secTail = elem as FamilySymbol;
                        string sectionTailName = sectionTail.Name;
                        if (char.IsDigit(sectionTailName[sectionTailName.Length - 1]))
                        {
                            sectionTailName = sectionTailName.Remove(sectionTailName.Length - 1);
                        }

                        if (secTail.Name.Contains(sectionTailName.Trim()))
                        {
                            sectionTailToDocId = secTail.Id;
                            break;
                        }
                    }
                    sectionTailToDocParameter.Set(sectionTailToDocId);

                    // Set Broken Section Display Style
                    Parameter brokenSectionDisplayStyleToDocParameter = sectionTagToDoc.LookupParameter("Broken Section Display Style");
                    brokenSectionDisplayStyleToDocParameter.Set(brokenSectionDisplayStyleValue);


                    t4.Commit();
                }
            }
            catch (Exception)
            {
                Autodesk.Revit.UI.TaskDialog.Show("Reference Error", $"Ugh... hate when this happens...\n\nThere was an issue creating the reference of detail {relatedDetail.ProjectDraftingView.Name} in detail {detail.ProjectDraftingView.Name}.\n\nSorry, you'll have to make the reference yourself.");
            }
        }

 

 

 

@jeremy_tammik - care to weigh in? 😊

Message 9 of 15

bshafiro
Autodesk
Autodesk

There is a way to copy drafting views with all the contents from one document to another. The important part is to have all drafting view ids and all view-specific element ids owned by the views in one set and one call to CopyElements(). Then reference callouts/sections and view references preserved correctly as long as they refer to other drafting views in this set. I've played recently with this workflow and here is a quick and dirty prototype of a macro that will copy all drafting views from active document to all other documents opened in Revit. I tested it, it does keep all the reference callouts with correct shapes and leader configurations and all view references (as long as they refer to drafting views).

public void CopyAllDraftingViews()
{
   Document activeDoc = this.ActiveUIDocument.Document;
   if (activeDoc == null)
      return;
   FilteredElementCollector coll = new FilteredElementCollector(activeDoc);
   ICollection<ElementId> viewIds = coll.OfClass(typeof(ViewDrafting)).ToElementIds();
   if (viewIds.Count == 0)
      return;

   IList<ElementId> allElementsToCopy = new List<ElementId>();

   foreach (ElementId viewId in viewIds)
   {
      allElementsToCopy.Add(viewId);
      FilteredElementCollector collVS = new FilteredElementCollector(activeDoc);
      ICollection<ElementId> viewOwnedIds = collVS.OwnedByView(viewId).ToElementIds();
      foreach (ElementId viewOwnedId in viewOwnedIds)
         allElementsToCopy.Add(viewOwnedId);
   }

   DocumentSet docSet = this.Application.Documents;


   foreach (Document doc in docSet)
   {
      if (doc.Title != activeDoc.Title)
      {
         Document targetDoc = doc;
         CopyPasteOptions options = new CopyPasteOptions();
         try
         {
            if (allElementsToCopy.Count() > 0)
            {
               using (Transaction t1 = new Transaction(targetDoc, "Copy views"))
               {
                  t1.Start();
                  ElementTransformUtils.CopyElements(activeDoc, allElementsToCopy, targetDoc, Transform.Identity, options);
                  t1.Commit();
               }

            }
         }
         catch (Exception)
         {
            throw;
         }
      }
   }
}


Boris Shafiro
Senior Manager, Software Development
LinkedIn
0 Likes
Message 10 of 15

matthew.joseph.frank
Participant
Participant

Boris, thank you for the response!

 

Unfortunately, when I ran this I receive the following exception :

"Autodesk.Revit.Exceptions.ArgumentException: 'Some of the elements cannot be copied, because they are view-specific. Parameter name: elementsToCopy'"

 

Here is my sandbox code:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Schaefer.RevitAddin.Commands.Sandbox
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class cmdSandboxMJF : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiApp = commandData.Application;
            UIDocument activeUiDoc = uiApp.ActiveUIDocument;
            Document activeDoc = activeUiDoc.Document;

            try
            {
                if (activeDoc != null) ;
                FilteredElementCollector coll = new FilteredElementCollector(activeDoc);
                ICollection<ElementId> viewIds = coll.OfClass(typeof(ViewDrafting)).ToElementIds();
                if (viewIds.Count == 0) ;

                IList<ElementId> allElementsToCopy = new List<ElementId>();

                foreach (ElementId viewId in viewIds)
                {
                    allElementsToCopy.Add(viewId);
                    FilteredElementCollector collVS = new FilteredElementCollector(activeDoc);
                    ICollection<ElementId> viewOwnedIds = collVS.OwnedByView(viewId).ToElementIds();
                    foreach (ElementId viewOwnedId in viewOwnedIds)
                        allElementsToCopy.Add(viewOwnedId);
                }

                DocumentSet docSet = uiApp.Application.Documents;


                foreach (Document doc in docSet)
                {
                    if (doc.Title != activeDoc.Title)
                    {
                        Document targetDoc = doc;
                        CopyPasteOptions options = new CopyPasteOptions();
                        try
                        {
                            if (allElementsToCopy.Count() > 0)
                            {
                                using (Transaction t1 = new Transaction(targetDoc, "Copy views"))
                                {
                                    t1.Start();
                                    ElementTransformUtils.CopyElements(activeDoc, allElementsToCopy, targetDoc, Transform.Identity, options);
                                    t1.Commit();
                                }

                            }
                        }
                        catch (Exception)
                        {
                            throw;
                        }
                    }
                }
                return Result.Succeeded;
            }
            catch (Exception)
            {                
                return Result.Failed;
                throw;
            }
        }
    }
}

 

0 Likes
Message 11 of 15

bshafiro
Autodesk
Autodesk

Hi Matthew,

 

This exception should not be thrown if elementsToCopy contains all viewIds of all vie-specific elements in elementsToCopy. But we had a bug when this exception was thrown erroneously in the correct cases. The bug was fixed in Revit 2024.

Most likely you are using Revit that is older than Revit 2024. Could you please confirm that? If yes, could you try your code in Revit 2024 or later?

Thank you!



Boris Shafiro
Senior Manager, Software Development
LinkedIn
0 Likes
Message 12 of 15

matthew.joseph.frank
Participant
Participant

Hey Boris!

 

I just confirmed this logic works in Revit 2024. Is there a work-around available for pre-2024? I still need to support back through 2022.

 

Thanks!

0 Likes
Message 13 of 15

bshafiro
Autodesk
Autodesk

Hi Matthew,

 

First of all, thank you for the confirmation. 

For the pre-2024 version of Revit you can try a different approach that might work for you. It has to consist of two separate API calls (in my case I tried macros) such that execution returns to Revit between them to make PostCommand() work. The code is below. I hope it helps:

      public void CopyAllDraftingViews()
      {
         Document doc = this.ActiveUIDocument.Document;
         if(doc == null)
            return;
         FilteredElementCollector coll = new FilteredElementCollector(doc);
         ICollection<ElementId> viewIds = coll.OfClass(typeof(ViewDrafting)).ToElementIds();
         if(viewIds.Count == 0)
            return;
         this.ActiveUIDocument.Selection.SetElementIds(viewIds);
         this.PostCommand(RevitCommandId.LookupPostableCommandId(PostableCommand.CopyToClipboard));
      }
      public void PasteIntoEmptyDoc()
      {
         UIApplication uiapp = new UIApplication(this.Application);
         uiapp.OpenAndActivateDocument("D:/EmptyDoc.rvt");
         this.PostCommand(RevitCommandId.LookupPostableCommandId(PostableCommand.PasteFromClipboard));
      }

 



Boris Shafiro
Senior Manager, Software Development
LinkedIn
0 Likes
Message 14 of 15

matthew.joseph.frank
Participant
Participant

Good morning, Boris!

 

Great idea in theory - unfortunately this exception exposes an API limitation here, as well:

Autodesk.Revit.Exceptions.InvalidOperationException
HResult=0x80131500
Message=Revit does not support more than one command are posted.
Source=RevitAPIUI
StackTrace:
at Autodesk.Revit.UI.UIApplication.PostCommand(RevitCommandId commandId)
at Schaefer.RevitAddin.Commands.Sandbox.cmdSandboxMJF.PasteIntoEmptyDoc(UIApplication uiApp, UIDocument activeUIDocument) in \\file01\IT_APPS\devOps\Schaefer.RevitAddinV2\Schaefer.RevitAddinV2\Commands\Sandbox\cmdSandboxMJF.cs:line 47
at Schaefer.RevitAddin.Commands.Sandbox.cmdSandboxMJF.Execute(ExternalCommandData commandData, String& message, ElementSet elements) in \\file01\IT_APPS\devOps\Schaefer.RevitAddinV2\Schaefer.RevitAddinV2\Commands\Sandbox\cmdSandboxMJF.cs:line 22

This exception was originally thrown at this call stack:
[External Code]
Schaefer.RevitAddin.Commands.Sandbox.cmdSandboxMJF.PasteIntoEmptyDoc(Autodesk.Revit.UI.UIApplication, Autodesk.Revit.UI.UIDocument) in cmdSandboxMJF.cs
Schaefer.RevitAddin.Commands.Sandbox.cmdSandboxMJF.Execute(Autodesk.Revit.UI.ExternalCommandData, ref string, Autodesk.Revit.DB.ElementSet) in cmdSandboxMJF.cs



Sandbox code:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Schaefer.RevitAddin.Commands.Sandbox
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class cmdSandboxMJF : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiApp = commandData.Application;
            UIDocument activeUiDoc = uiApp.ActiveUIDocument;

            try
            {
                CopyAllDraftingViews(uiApp, activeUiDoc);
                PasteIntoEmptyDoc(uiApp, activeUiDoc);
                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                message = $"Error: {ex.Message}";
                return Result.Failed;
            }
        }

        public void CopyAllDraftingViews(UIApplication uiApp, UIDocument activeUIDocument)
        {
            Document doc = activeUIDocument.Document;
            if (doc == null)
                return;
            FilteredElementCollector coll = new FilteredElementCollector(doc);
            ICollection<ElementId> viewIds = coll.OfClass(typeof(ViewDrafting)).ToElementIds();
            if (viewIds.Count == 0)
                return;
            activeUIDocument.Selection.SetElementIds(viewIds);
            uiApp.PostCommand(RevitCommandId.LookupPostableCommandId(PostableCommand.CopyToClipboard));
        }
        public void PasteIntoEmptyDoc(UIApplication uiApp, UIDocument activeUIDocument)
        {
            uiApp.OpenAndActivateDocument("C:/Users/frankm/Downloads/Library.rvt");
            uiApp.PostCommand(RevitCommandId.LookupPostableCommandId(PostableCommand.PasteFromClipboard));
        }
    }
}

 

0 Likes
Message 15 of 15

bshafiro
Autodesk
Autodesk

Yes, that is what I meant, but did not explain it properly. I had 2 macros: executed the first one by pressing a button in the macro manager and then executed the second one. Thus, Revit had control in the interactive mode between the macro executions and that is when the first posted message went through. You cannot call these two methods consecutively in the API since this would lead to the exception you saw. Alternatively, you can have a modeless dialog in an API application with 2 buttons: pressing the first button would execute the first method (copy) and pressing the second button would execute the second method (paste). This would require some user interaction though, and that might not be appropriate to your workflow.



Boris Shafiro
Senior Manager, Software Development
LinkedIn
0 Likes