When you have 2 revit projects open and want to switch between them it can be done with:
application.OpenAndActivateDocument(file).
In order to get the filename I used the get it with Document.PathName.
Now I come accross problems with files on Revit Server and BIm 360 docs. Their Document.Pathname stays empty.
So, my questions is, how do I switch between those documents (when Document.Pathname is empty) ?
Is there a way to switch between documents without having to specify the file name ?
Solved! Go to Solution.
Solved by RPTHOMAS108. Go to Solution.
The only way I have found is indirectly via UIDocument.ShowElements. You pick an element from the DB document you want to change to, create a UIDocument object from a DB document and use UIDocument.ShowElements. You have to handle the occasional “No good view found” dialogue but it seems to always switch the active document regardless of what is found. Helps if it is a View specific element.
Not sure if there is a better way, also wondering when future implementation of .ActiveUIDocument is coming (as noted in RevitAPI.chm file). Odd that there seems to be no way to do this directly.
"External API commands can access this property in read-only mode only! The ability to modify the property is reserved for future implementations."
Haha, never thought of this approach 🙂 thanks. "Odd that there seems to be no way to do this directly" Yeah, and even stranger they make an "OpenAndActivate", while the file is already openend. A simple "SetActiveDocument" would be enough.
Many thanks to @RPTHOMAS108 for the solution!
Also documented here:
"The first issue that arises is that the mirror command requires a current active view, which is not automatically present in the family document. Joe discovers a workaround for that issue using the ShowElements method. It generates an unwanted warning message, so a second step is required to deal with eliminating that as well.
As you can see on reading the final solution carefully, you can use the ShowElements method to change the active view and even switch it between the family and project documents. The official Revit 2011 API does not provide any method to switch the active view, but using ShowElements can be used to create a workaround for that."
Cheers,
Jeremy
Thanks Jeremy,
It's the same conclusion as RPTHOMAS108 posted 🙂
Well, I gave it a shot on the Revit Ideas site: Revit Idea
So, everyone who reads this post, please vote, so AutoDesk will notice and maybe put this functionality in the next Revit 🙂
Hmm, close but no sigar 😞
I start with document A. Later I open Document B which becomes the active document. I use the showelements to open a view from Document B, so it becomes the active document. Then I use DOcB.Close(false) and revit keeps telling me it can't do that because of some subtransaction being active??? No idea what transaction Revit means 😞
Dear Remy,
I never heard of that problem before.
Here are two exploration of closing documents... don't know whether they will be of any use in your case:
Cheers,
Jeremy
The exact message reads: Revit encountered a Autdesk.Revit.Exceptions.InvalidOperationException: Close is not allowed when there is any open sub-transaction, transaction or transaction group.
What I do is:
In a project, open family, do some actions within a transaction which I commit and afterwards dispose. Then save the family. Use the showelements option to get a view of the project active and then try to close the family. That is when this errors comes.
Dear Remy,
Sounds weird.
If you want the development team (or anyone else, for that matter) to be able to take a look, please provide a complete minimal reproducible case including sample model, macro and exact steps to reproduce:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
Cheers,
Jeremy
It is pretty easy to reproduce:
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
[Journaling(JournalingMode.NoCommandData)]
public class DrieBToolTest : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
// select some elements in the first document
FilteredElementCollector notElemTypeCtor = (new FilteredElementCollector(doc, uidoc.ActiveGraphicalView.Id)).WhereElementIsNotElementType();
List<ElementId> theelems = notElemTypeCtor.ToList().Select(theelem => theelem.Id).ToList();
// open the second file and do some actions
string fam = @"d:\test\fam\31_3B_vo bu deur met weerszijde 2 zijlichten.rfa";
UIDocument famDoc = commandData.Application.OpenAndActivateDocument(fam);
Transaction transac = new Transaction(famDoc.Document);
transac.Start("change scale");
famDoc.ActiveView.get_Parameter(BuiltInParameter.VIEW_SCALE_PULLDOWN_METRIC).Set(20);
transac.Commit();
SaveAsOptions opt = new SaveAsOptions { OverwriteExistingFile = true };
famDoc.Document.SaveAs(fam, opt);
// On a new file the doc,PathName is empty
if (!string.IsNullOrEmpty(doc.PathName))
{
commandData.Application.OpenAndActivateDocument(doc.PathName);
famDoc.Document.Close(false); // no problem here
}
else
{
// this is the way to go when to avoid using OpenAndActivateDocument
uidoc.ShowElements(theelems);
uidoc.RefreshActiveView();
famDoc.Document.Close(false); //here revit throws the exception and doesn't close the file
}
return Result.Succeeded;
}
Please also describe the exact steps to reproduce the problem. Thx!
Sorry to hear this doesn't work.
To be honest I don't think I've actually needed to save after using this trick since I'm usually either opening and activating (in the case of a add-in that processes multiple files) or just working in the current file within an IExternalCommand context.
I do get this same exception for something unrelated, where I open detached. Hard to diagnose these things when you have other add-ins running which may be opening transactions during events etc.
Dear Remy,
I have not yet submitted this to the development team.
I did take a closer look at your code now, at least, and have some minor improvement suggestions as follows:
/// <summary> /// Toggle back and forth between two different documents /// </summary> void ToggleViews( View view1, string filepath2 ) { Document doc = view1.Document; UIDocument uidoc = new UIDocument( doc ); Application app = doc.Application; UIApplication uiapp = new UIApplication( app ); // Select some elements in the first document ICollection<ElementId> idsView1 = new FilteredElementCollector( doc, view1.Id ) .WhereElementIsNotElementType() .ToElementIds(); // Open the second file UIDocument uidoc2 = uiapp .OpenAndActivateDocument( filepath2 ); Document doc2 = uidoc2.Document; // Do something in second file using( Transaction tx = new Transaction( doc2 ) ) { tx.Start( "Change Scale" ); doc2.ActiveView.get_Parameter( BuiltInParameter.VIEW_SCALE_PULLDOWN_METRIC ) .Set( 20 ); tx.Commit(); } // Save modified second file SaveAsOptions opt = new SaveAsOptions { OverwriteExistingFile = true }; doc2.SaveAs( filepath2, opt ); // Switch back to original file; // in a new file, doc.PathName is empty if( !string.IsNullOrEmpty( doc.PathName ) ) { uiapp.OpenAndActivateDocument( doc.PathName ); doc2.Close( false ); // no problem here, says Remy } else { // Avoid using OpenAndActivateDocument uidoc.ShowElements( idsView1 ); uidoc.RefreshActiveView(); //doc2.Close( false ); // Remy says: Revit throws the exception and doesn't close the file } }
The things I care about here are:
It probably won't change the problem of closing the family, though.
Cheers,
Jeremy
Edited and saved for posterity here:
http://thebuildingcoder.typepad.com/blog/2018/03/switch-view-or-document-by-showing-elements.html
Cheers,
Jeremy
I had such problems with transaction when I after changeng ActiveDocument close document.
I solve this through external event.
//After all logic i call external event
//Glob is static clase where i store some constant and use for easy Glob.GeneralEventWithParams.RunFunc(CloseDoc, Glob.GeneralExternalEventWithParams, famDoc); ui_doc.ShowElements(new List<ElementId> { ins.Id }); ui_doc.RefreshActiveView();
//Method that i use for closing and call inside event
public static bool CloseDoc(UIDocument ui_doc, params object [ ] obk) { var doc = obk [ 0 ] as Document; doc.Close(false); return true;
//External event that i use
public class GeneralExternalEventWithParams :IExternalEventHandler { private Func<UIDocument, object [ ], bool> Function { get; set; } public void Execute(UIApplication app) { try { var ui_doc = app.ActiveUIDocument; var doc = ui_doc.Document; if ( Function != null ) { Function?.Invoke(ui_doc, Params); } } catch ( Exception e ) { e.WriteEx(); } } public void RunFunc(Func<UIDocument, object [ ], bool> function, ExternalEvent runningEvent, params object [ ] parameters) { try { Function = function; Params = parameters; runningEvent.Raise(); } catch ( Exception e ) { } } public object [ ] Params { get; set; } public string GetName() { return "GeneralExternalEventWithParams"; } }
Hi, coming from the future 🙂
I personally use UIDocument.RefreshActiveView() and it seem work for me.
From the even more distant future: I've found, that after changing the active document with uiDoc.ShowElements() I'm not able to close the previous document with oldUiDoc.SaveAndClose(), it does nothing, no exceptions thrown, but instead of returning the expected boolean it jumps right into my IdlingEventHandler.
Seems similar to https://forums.autodesk.com/t5/revit-api-forum/closing-active-family-document/m-p/11471099/highlight... but the alternate method is not always available...
I did some further investigation, and found the connection between the issue mentioned in the linked topic.
While my code did not throw any exceptions in Visual Studio (silly me had no try-catch around the specific code), I've found an exception in the Journal:
' 0:< External event handler <RevitExternalEventHandler> failed with an exception {Close is not allowed when there is any open sub-transaction, transaction or transaction group.}. The event was registered by an AddIn ...(a guid)
So it seems that it is not possible to close a document (neither using doc.Close() nor uiDoc.SaveAndClose()) after activating another document via uidoc.ShowElements() if we are in a valid API context (ExternalCommand or ExternalEvent). However there are no issues at all when whe are "outside of valid API context", and I execute my code on a cached UIApplication. I've tried to do everything by the book, and only interact with the Revit API in valid API context, but this case looks like an exception from the general rule, where it should be avoided.
@jeremytammikcould you please put up this issue to the development team for further investigation?
Well, the exception to the general rule probably means that you found a loophole that the development team will be happy to close, and then what you are after will not work in that form any more at all. Maybe you can work around the issue by combining the external event with a one-off Idling event? Afaik, there are no restrictions at all on what you can do in an Idling event handler, whereas, according to the journal entry you share, certain restrictions do apply to external events.
Can't find what you're looking for? Ask the community or share your knowledge.