Extra Transaction Required

Here is another interesting issue to discuss in between the series of instalments of background information on the Revit API geometry library from Scott’s Autodesk University presentation on

analysing building geometry
.

As we mentioned repeatedly in the past, Revit automatically opens a transaction when an external command is invoked, and closes or aborts it when the command terminates, depending on the command result returned by the Execute method.
This affects the

document IsModified property
and
clarifies why you need to open you own transactions for certain

event handlers
and

modeless dialogues
,
forcing you to take on some

transaction responsibility
yourself.
It is therefore always easier and more robust to

use a modal dialogue
instead of a modeless one, if that is possible.

Here is an example from a case handled by Joe Ye of a situation where we are forced to open our own transaction in spite of executing code within a normal modal external command context.
This is because in this specific situation, certain actions of our command depend on previous actions having completed, and this does apparently not always happen automatically.
By encapsulating the first step in its own transaction and closing that, the second step depending on it can execute correctly as well.

Question: I have created a new I beam in my Revit model.
I then use the Revit API to apply the following modifications to it:

  1. Change the beam’s “Vertical Projection” property to “Center of Beam”.
  2. Change the beam’s “Z Direction Justification” property to “Center”.
  3. Create two rectangular openings to hold the beam using the beam’s start and end points as center points and defining rectangles around them.

Of the two openings, the first is created in the wrong position, while the second one, at the end of the beam, is created correctly.
It seems as if the first opening is created before the “Z Direction Justification” is changed, and the second one afterwards.

Answer: This issue has to do with the model update.
The changes to the Z direction justification and vertical projection properties modify the model.
Apparently, these changes have not yet been completely applied to the model before the creation of the openings is launched.
The complete changes are only guaranteed to be applied to the model after the external command has completely terminated and its automatic transaction has been closed.

In this case, it appears that the property modifications have not been applied when the first opening is created.
The creation of the first opening affects the model in a way as to apply the property modifications as well, and therefore the second opening can make use of the updated properties, whereas the first one could not.
This explains why the first opening ended up in the wrong position and the second was correct.

The solution for this is to add a transaction to encapsulate the process of changing the two parameter values.
This makes sure the beam is updated.
After modifying the properties and closing the transaction, the two openings can be added successfully.

Here is a sample code snippet demonstrating this:


using RvtElement = Autodesk.Revit.Element;
using CreationDocument = Autodesk.Revit.Creation.Document;
public IExternalCommand.Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
{
  Application app = commandData.Application;
  Document doc = app.ActiveDocument;
  View view = commandData.View;
 
  ElementSet elemSet = view.Elements;
 
  IEnumerator elementEnumerator
    = elemSet.ForwardIterator();
 
  while( elementEnumerator.MoveNext() )
  {
    FamilyInstance fi = elementEnumerator.Current
      as FamilyInstance;
 
    if( null != fi )
    {
      CurveArray curves = new CurveArray();
 
      app.ActiveDocument.BeginTransaction();
 
      // set the Vertical Projection
 
      Parameter p = fi.get_Parameter(
        BuiltInParameter.BEAM_V_JUSTIFICATION );
 
      p.Set( 1 );
 
      p = fi.get_Parameter( BuiltInParameter
        .STRUCTURAL_ANALYTICAL_PROJECT_MEMBER_PLANE );
 
      if( p != null )
      {
        ElementId elemId = p.AsElementId();
 
        elemId.Value = -3;
 
        p.Set( ref elemId );
      }
 
      // Vertical Projection modification ends here
 
      app.ActiveDocument.EndTransaction();
 
      LocationCurve lc = fi.Location as LocationCurve;
 
      XYZ pointOnPlane = lc.Curve.get_EndPoint( 0 );
 
      XYZ hostY = fi.FacingOrientation;
      XYZ hostX = fi.HandOrientation;
      XYZ hostZ = hostX.Cross( hostY );
 
      curves = CreateRectangle( app, pointOnPlane,
        hostX, hostZ, 0.5, 0.5 );
 
      Opening opening = doc.Create.NewOpening( fi,
        curves, CreationDocument.eRefFace.CenterY );
 
      pointOnPlane = lc.Curve.get_EndPoint( 1 );
 
      curves = CreateRectangle( app, pointOnPlane,
        hostX, hostZ, 0.5, 0.5 );
 
      opening = doc.Create.NewOpening( fi,
        curves, CreationDocument.eRefFace.CenterY );
    }
  }
  return IExternalCommand.Result.Succeeded;
}

So the motto of this is that if you need to perform some model change immediately after some other model changing action, and the second change is closely related to the first, then it is safer to encapsulate the first change in a transaction to ensure that the second one correctly honours it.

Many thanks to Joe for handling this case!


Comments

2 responses to “Extra Transaction Required”

  1. Hi Jeremy,
    A Question: if you return “Cancelled” or “Failed” for the automatically generated transaction, does this still roll back the changes made in the manually created nested transaction? i assume it would.

  2. Dear Krispy,
    Good question! I would assume so too. On the other hand, I follow the maxim of the German sayings “traue niemand ueber dreissig” and “vertrauen ist gut, kontrolle ist besser”: “trust nobody over 30”, and “trust is good, checking it out is better”.
    If you really want to know for sure, you cannot trust me or any documentation. The only place to put your trust is in the source code and your own foolproof testing.
    So please check it out and let us know.
    We’ll trust your resulting statements on it :-)
    Cheers, Jeremy.

Leave a Reply to Jeremy TammikCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading