Edit parameter on FileExporting event

Edit parameter on FileExporting event

Anonymous
Not applicable
1,183 Views
11 Replies
Message 1 of 12

Edit parameter on FileExporting event

Anonymous
Not applicable

I'm trying to create a script that ensures that a certain parameter is updated before the file is exported. The problem is that everything inside the transaction is omitted. What can I do to solve this?

 

This is what I have done so far:

I found AutoUpdate in SDK samples that changes ProjectInformation.Address property on DocumentOpened.

 

According to revitapidocs.com you are allowed to make changes to the document (I have checked that .IsReadOnly returns false).

 

Remarks

This event is raised when Revit is just about to export files of formats supported by the API.

Handlers of this event are permitted to make modifications to any document (including the active document), except for documents that are currently in read-only mode.

Event is cancellable. To cancel it, call the 'Cancel()' method in event's argument to True. Your application is responsible for providing feedback to the user about the reason for the cancellation.

The following API functions are not available for the current document during this event:

All overloads of Autodesk.Revit.DB.Document.Export()
Autodesk.Revit.Document.Print()
Print and similar overloads.
SubmitPrint and similar overloads.
Close and similar overloads.
Save .
SaveAs(String) and similar overloads.

Here is a simple application macro that is supposed to set the comments parameter to a beam to "test". To test it run the ExportEventRegister() macro first, then export the file to trigger the event.

 

		public void ExportEventRegister() {
			this.Application.FileExporting += new EventHandler<FileExportingEventArgs>(myExportingEvent);
		}

		private void myExportingEvent(object sender, FileExportingEventArgs args) {
			FilteredElementCollector fec = new FilteredElementCollector(args.Document).OfCategory(BuiltInCategory.OST_StructuralFraming).WhereElementIsNotElementType();
			Transaction t1 = new Transaction(args.Document, "test");
		    t1.Start();
			foreach (Element element in fec) {
	      		element.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).Set("test");
			}
		    t1.Commit();
		}

 

0 Likes
1,184 Views
11 Replies
Replies (11)
Message 2 of 12

jeremytammik
Autodesk
Autodesk

You could try to open a transaction group, open a transaction, make the parameter change, commit the transaction, then open a second transaction for the export operation, commit that, and assimilate the whole group:

 

http://thebuildingcoder.typepad.com/blog/2013/04/transactions-sub-transactions-and-transaction-group...

 

http://thebuildingcoder.typepad.com/blog/2014/11/cloud-accelerator-vdc-and-transaction-groups.html#4

 

http://thebuildingcoder.typepad.com/blog/2015/02/using-transaction-groups.html

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 12

Revitalizer
Advisor
Advisor

Hi,

 

change this...

foreach (Element element in fec)

 

...to that:
foreach (Element element in fec.ToElements())

 

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 4 of 12

jeremytammik
Autodesk
Autodesk

H Rudi,

 

Why do you suggest that?

 

You can iterate directly over a filtered element collector.

 

Furthermore, ToElements can introduce an inefficiency for large numbers of elements.

 

It forces .NET to copy all the elements into a new collection:

 

http://thebuildingcoder.typepad.com/blog/2012/05/family-usage-filtered-element-collector-performance...

 

"One thing that I note which will cost you some unnecessary time is the conversion of collectors to collections, for instance:

 

  Dim collection As ICollection(
      Of Autodesk.Revit.DB.Element)
    = collector.OfClass(GetType(DB.Family))
      .ToElements()

 

There is no need for this conversion; you can iterate over the collector itself directly, so there is no reason to create a collection, which requires memory allocation and a conversion overhead.

 

Eliminating the conversion to collections will only have a small impact, though. Try it out; benchmark this and let me know the result, please."

 

Please correct me if I am wrong!

 

Thank you!

 

Cheers,

 

jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 12

Anonymous
Not applicable

Thank you very much for the answers gentlemen!

 

I have one more observation to add: This works perfectly fine when I export to DWG, but fails for IFC. My suspicion is that the open source IFC exporter is blocking the transaction somehow. I tried to look in the source code for the IFC-exporter for clues, but that's not a small task.

 

Jeremy: "then open a second transaction for the export operation"

 

I'm not sure what to put in the second transaction, I guess that the export operation is already started? 

0 Likes
Message 6 of 12

DavidWoodCT
Enthusiast
Enthusiast

Edit: Ah, OK, yes, it works for me for DWG also.

 

What is the transaction status after the commit?

0 Likes
Message 7 of 12

jeremytammik
Autodesk
Autodesk

Oh I see.

 

The callback is called from within the export operation.

 

I guess the DWG export has closed its own transaction before calling the callback, whereas the IFC export keeps its transaction open.

 

You might try to make your modification within the event handler without opening your own transaction.

 

And then call document.Regen to make sure the change is taken into account before the IFC export continues.

 

Cheers,

 

jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 8 of 12

Anonymous
Not applicable

I found this in the source of the IFC exporter ( \IFCExporterUIOverride\IFCCommandOverrideApplication.cs):

 

                  Transaction transaction = new Transaction(document, "Export IFC");
                  transaction.Start();
---
                  bool result = document.Export(path, fileName, exportOptions);
---
                  // Roll back the transaction started earlier, unless certain options are set.
                  if (result && (use2009BuildingStoreyGUIDs || selectedConfig.StoreIFCGUID))
                     transaction.Commit();
                  else
                     transaction.RollBack();

The FileExporting Event is probably triggered by document.Export(). That is where my code kicks in! In most cases the transaction is rolled back, but one exception is when the Store IFC Guid option is ticked, and in that case my code is working! So that is at least a workaround.

 

Is there a way to chime in before the IFC Exporter UI is started? I have not figured out how the IFC exporter knows that the export ifc button is pressed.

 

Regards,

Einar Raknes

0 Likes
Message 9 of 12

jeremytammik
Autodesk
Autodesk

Congratulations on discovering the workaround and finding the reason for this behaviour!

 

Is there a way to chime in before the IFC Exporter UI is started?

 

You might be able to redefine the built-in Revit IFC export command and replace it by your own which first does whatever you want:

 

http://thebuildingcoder.typepad.com/blog/2012/06/replacing-built-in-commands-and-their-ids.html

 

After doing its job, you might be able to use PostCommand to launch the original built-in command afterwards:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.3

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 10 of 12

Anonymous
Not applicable

Jeremy,

 

Thank you for the encouragement and helpful links! "CommandBinding" was the keyword I needed to figure out how the IFC exporter is initiated. It is indeed overriding the command with id "ID_EXPORT_IFC". I suspect there will be trouble if I try to override the same command? I might have to find another approach, for instance look into building a custom exporter on top of the existing: https://sourceforge.net/p/ifcexporter/wiki/Adding%20Custom%20Property%20Sets/

 

Here is the IFCCommandOverrideApplication class in the open source IFC addin:

 

 

   public class IFCCommandOverrideApplication : IExternalApplication
   {
      #region IExternalApplication Members

      /// <summary>
      /// The binding to the Export IFC command in Revit.
      /// </summary>
      private AddInCommandBinding m_ifcCommandBinding;

      /// <summary>
      /// Implementation of Shutdown for the external application.
      /// </summary>
      /// <param name="application">The Revit application.</param>
      /// <returns>The result (typically Succeeded).</returns>
      public Result OnShutdown(UIControlledApplication application)
      {
         // Clean up
         m_ifcCommandBinding.Executed -= OnIFCExport;

         return Result.Succeeded;
      }

      /// <summary>
      /// Implementation of Startup for the external application.
      /// </summary>
      /// <param name="application">The Revit application.</param>
      /// <returns>The result (typically Succeeded).</returns>
      public Result OnStartup(UIControlledApplication application)
      {
         TryLoadCommonAssembly();

         // Register execution override
         RevitCommandId commandId = RevitCommandId.LookupCommandId("ID_EXPORT_IFC");
         try
         {
            m_ifcCommandBinding = application.CreateAddInCommandBinding(commandId);

         }
         catch
         {
            return Result.Failed;
         }

         m_ifcCommandBinding.Executed += OnIFCExport;
         return Result.Succeeded;
      }

 

0 Likes
Message 11 of 12

jeremytammik
Autodesk
Autodesk

If it looks like that, the easiest might just be for you to add a call to your code right at the beginning of the open source IFC external command.

 

You could even implement it in a way that makes the call if your code is available (e.g., in a class library in a specific location, e.g., in the same folder as the open source IFC DLL) and just does nothing otherwise.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 12 of 12

jeremytammik
Autodesk
Autodesk

You should probably discuss this question with the dedicated experts in the IFC open source forum.



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes