This is The Building Coder post number 1700.
It is a great pleasure to return to the Revit API discussion forum question on how to combine multiple transactions into one undo and highlight a comeback and new answer by Arnošt Löbel, ex Senior Principal Engineer of the Revit development team.
The beginning of that thread and Arnošt's previous answers were already presented here in the blog in the discussion on using transaction groups.
Question: Hi Arnost Lobel:
I have read your reply, and looked into the TransactionGroup.Assimilate
method in the Revit API help document .chm
file.
I found that this method takes no parameters.
What I want to ask is:
Assimilate
, will this ahead started one also be assimilated into the group?Execute
method) with the transaction group still open. See my code:public void Execute( RvtUiApplication app ) { if( WpfTarget.Transactions.ContainsKey( this.GetName() ) ) { Transaction = WpfTarget.Transactions[GetName()]; if( Transaction == null ) { Transaction = new Transaction( WpfTarget.CmdVars.DbDoc, GetName() ); WpfTarget.Transactions[GetName()] = this.Transaction; } } else { WpfTarget.Transactions.Add( GetName(), new Transaction( WpfTarget.CmdVars.DbDoc, GetName() ) ); } WpfTarget.TransGroup.Start(); Transaction.Start(); Level.Create( WpfTarget.CmdVars.DbDoc, 30 ); Transaction.Commit(); WpfTarget.TransGroup.Assimilate(); }
Just ignore the head part of this Execute
method, they are for my own WPF window. Notice that before leaving this external event handler context, I called only Assimilated
, but not Rollback
or Commit
.
I ran these codes without debugging, and Revit threw no errors.
Tested in API ver 2018.
If running in VS debugger, single stepping out of this method displays a page like this:
Does it mean that I can 'modelessly' use TransactionGroup
?
Answer: Now this is rather funny, I think. I have found this post accidentally while googling up something else which had my name in it. I was surprised to see a new question to a very old post I had participated in, and even more I was surprised to find the question unanswered. I do not work for Autodesk anymore, but since the transaction API was kind of a favourite of mine when I worked on the API, I kind of feel somehow obligated to answer such questions. I mean – I would not look for them purposely, of course, but if I come across one, I’ll answer it if I can.
To your questions:
TransactionGroup.Start
method would throw an exception in such a situation. To test whether there is a transaction open, you can use the Document.IsModifiable
method.I hope it makes sense what I wrote.
I also have one comment about your code. One thing that is not quite clear to me is what happens if your container of transactions does not have an entry for this.GetName
; The code would proceed to the Else
block in which a new transaction is instantiated and added to your container of transactions. However, the member this.Transaction
is not updated, which seems strange with respect to the rest of your code. After you leave your if-else block and you start your transaction group, you then call Transaction.start
– which transaction would that be? Do you have a global Transaction
instance? I assume you do, because in this particular case your this.Transaction
would not be set to the new transaction you instantiated inside the Else
block. My guess is that you would start and commit a different transaction (if there was one instantiated before), which would have a different name. Of course, you would not notice that if you successfully assimilated the transaction group, which is probably why that detail escaped you.
Very many thanks to Arnošt for jumping in and helping out again!
I hope you are having a great time and enjoying life post-Revit!