ModificationOutsideTransactionException when copying ViewTemplates to a new project file

ModificationOutsideTransactionException when copying ViewTemplates to a new project file

DanielKP2Z9V
Advocate Advocate
500 Views
4 Replies
Message 1 of 5

ModificationOutsideTransactionException when copying ViewTemplates to a new project file

DanielKP2Z9V
Advocate
Advocate

I'm trying to export selected ViewTemplates (using a custom winform) to a new project file, so they can be imported into another project. However, ElementTransformUtils.CopyElements (line 54) yields a ModificationOutsideTransactionException even though it's wrapped inside a Transaction (line 41).

 

Does anyone know what may be causing it?

 

 

 

 

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

namespace scripts
{
    [Transaction(TransactionMode.Manual)]
    public class ExportViewTemplatesToRvt : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiApp = commandData.Application;
            UIDocument uiDoc = uiApp.ActiveUIDocument;
            Document doc = uiDoc.Document;

            // Get all view templates in the document
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            List<Autodesk.Revit.DB.View> viewTemplates = collector.OfClass(typeof(Autodesk.Revit.DB.View))
                                                        .Cast<Autodesk.Revit.DB.View>()
                                                        .Where(v => v.IsTemplate)
                                                        .ToList();

            List<string> properties = new List<string> { "Title" };

            var selectedViews = CustomGUIs.DataGrid<Autodesk.Revit.DB.View>(viewTemplates, properties);

            // Prompt user to choose location and file name
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Revit File (*.rvt)|*.rvt";
            saveFileDialog.Title = "Save As";
            saveFileDialog.ShowDialog();

            // Check if the user cancelled the operation
            if (saveFileDialog.FileName == "")
                return Result.Cancelled;

            // Start a transaction
            using (Transaction transaction = new Transaction(doc, "Export View Templates"))
            {
                transaction.Start();

                // Create a new Revit document
                var revitApp = uiApp.Application;
                Document newDoc = revitApp.NewProjectDocument(UnitSystem.Imperial);

                // Copy the selected elements to the new document
                List<ElementId> copiedIds = new List<ElementId>();
                foreach (Autodesk.Revit.DB.View viewTemplate in viewTemplates)
                {
                    CopyPasteOptions copyOptions = new CopyPasteOptions();
                    ElementId copiedId = ElementTransformUtils.CopyElements(doc, new List<ElementId> { viewTemplate.Id }, newDoc, Transform.Identity, copyOptions).FirstOrDefault();
                    copiedIds.Add(copiedId);
                }

                // Save the new document as .rvt
                string filePath = saveFileDialog.FileName;
                SaveAsOptions saveAsOptions = new SaveAsOptions { OverwriteExistingFile = true };
                newDoc.SaveAs(filePath, saveAsOptions);

                // Commit the transaction
                transaction.Commit();

                TaskDialog.Show("Success", "Selected objects have been exported to a new .rvt file.");
            }
            return Result.Succeeded;
        }
    }
}

 

 

 

0 Likes
Accepted solutions (1)
501 Views
4 Replies
Replies (4)
Message 2 of 5

Moustafa_K
Collaborator
Collaborator
Accepted solution

you have 2 issues with your code.

First, you opened a transaction at the source document, this document you are not going to change, you are just reading the templates, by which you are going to supply to the new Document. Thus, you need to open a transaction from the new Document.

something like this

 Document newDoc = revitApp.NewProjectDocument(UnitSystem.Imperial);
 
           // Start a transaction
           using (Transaction transaction = new Transaction(newDoc, "Export View Templates"))
           {
               transaction.Start();

... past your templates

           // Commit the transaction
               transaction.Commit();
            }
               // Save the new document as .rvt 
               SaveAsOptions saveAsOptions = new SaveAsOptions { OverwriteExistingFile = true }; 
               newDoc.SaveAs(filePath, saveAsOptions);

the second issue, you can never save a document before you commit a transaction. 

 

so the steps to follow

1. get all the templates you need

2. create the new document

3. open transaction from the new document

4. past all your templates

5. commit transaction

6. save the the new document

 

 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
Message 3 of 5

DanielKP2Z9V
Advocate
Advocate

thank you, that solved it. the final script seems to have some issues though (copies materials, families and everything else, not just the view template), but that's not related directly to this problem.

0 Likes
Message 4 of 5

DanielKP2Z9V
Advocate
Advocate

okay, now it works fine - updated code below. It exports selected view template into a new empty project in reasonable time.

That "copies everything, not just the view template" issue was just a simple omission in foreach loop (line 54 below). I've also added "suppress duplicate types" for convenience from here and close the file handle after it finishes.

 

 

 

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

namespace scripts
{
    [Transaction(TransactionMode.Manual)]
    public class ExportViewTemplatesToRvt : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiApp = commandData.Application;
            UIDocument uiDoc = uiApp.ActiveUIDocument;
            Document doc = uiDoc.Document;

            // Get all view templates in the document
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            List<Autodesk.Revit.DB.View> viewTemplates = collector.OfClass(typeof(Autodesk.Revit.DB.View))
                                                        .Cast<Autodesk.Revit.DB.View>()
                                                        .Where(v => v.IsTemplate)
                                                        .ToList();

            List<string> properties = new List<string> { "Title" };

            var selectedViews = CustomGUIs.DataGrid<Autodesk.Revit.DB.View>(viewTemplates, properties);

            if (selectedViews.Count == 0)
                return Result.Cancelled;

            // Prompt user to choose location and file name
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Revit File (*.rvt)|*.rvt";
            saveFileDialog.Title = "Save As";
            saveFileDialog.ShowDialog();

            // Check if the user cancelled the operation
            if (saveFileDialog.FileName == "")
                return Result.Cancelled;

            // Create a new Revit document
            var revitApp = uiApp.Application;
            Document newDoc = revitApp.NewProjectDocument(UnitSystem.Metric);

            // Start a transaction
            using (Transaction transaction = new Transaction(newDoc, "Export View Templates"))
            {
                transaction.Start();

                // Copy the selected elements to the new document
                List<ElementId> copiedIds = new List<ElementId>();
                foreach (Autodesk.Revit.DB.View selectedViewTemplate in selectedViews)
                {
                    CopyPasteOptions copyOptions = new CopyPasteOptions();
                    copyOptions.SetDuplicateTypeNamesHandler(new DuplicateTypesHandler());
                    ElementId copiedId = ElementTransformUtils.CopyElements(doc, new List<ElementId> { selectedViewTemplate.Id }, newDoc, Transform.Identity, copyOptions).FirstOrDefault();
                    copiedIds.Add(copiedId);
                }

                // Commit the transaction
                transaction.Commit();

                TaskDialog.Show("Success", "Selected objects have been exported to a new .rvt file.");
            }

            // Save the new document as .rvt
            string filePath = saveFileDialog.FileName;
            SaveAsOptions saveAsOptions = new SaveAsOptions { OverwriteExistingFile = true };
            newDoc.SaveAs(filePath, saveAsOptions);
            newDoc.Close(false); // Pass false to indicate that changes should not be saved


            return Result.Succeeded;
        }
    }
}

 

 

 

0 Likes
Message 5 of 5

Moustafa_K
Collaborator
Collaborator

So glad that you made it work. thanks for sharing your insights

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes