Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Purge Unused Via the API

25 REPLIES 25
SOLVED
Reply
Message 1 of 26
Anonymous
10137 Views, 25 Replies

Purge Unused Via the API

So I've read this:

http://thebuildingcoder.typepad.com/blog/2013/03/determining-purgeable-elements.html

and this: 

http://forums.autodesk.com/t5/revit-api/writing-a-purge-utility/m-p/2735359/highlight/true#M1726

 

and they say that triggering the "Purge Unused" button under the "Manage" tab via code isn't possible and that you have to write your own code to handle the not so small task of doing it manually.

PurgeUnused.PNG (this button)

 

 

I also noted that both those posts are from around 3 years ago. I was wondering if there was an update on this. I can't find an API specific road map for features with a cursory google search, anyone know if there is one?

 

I don't want to rewrite code that already exists, especially when it sounds like it's a sizeable project in its own right! It's tantalizingly out of reach and replicating it would feel like time wasted.

 

Is it already in the API and I just can't find it? Are there plans to put it into the API if not? Should I wait for it to turn up in the API or grit my teeth and code my own solution? Should I just split my program and demand people press the button manually in the worst UX since MS-DOS?

 

 

 

25 REPLIES 25
Message 2 of 26
jeremytammik
in reply to: Anonymous

Dear Tomslabs,

 

Thank you for raising this issue again.

 

Sorry to hear that you don't like the UX.

 

Anyway, regarding your request, it is high on the development team's radar, and we have several related issues in the development database.

 

I added your notes to the wish list item CF-1201 [Purge unused objects] to underline its importance.

 

Cheers,

 

Jeremy

 

 

 

 

 



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

Message 3 of 26
Anonymous
in reply to: jeremytammik

Oh, brilliant, thanks!

 

I meant that the UX of my own add-in would be terrible if I made it that way. Rereading it, I can see why you'd think I was talking about the Revit UX in general!

 

The UX of Revit/ the API is good!

Message 4 of 26
Anonymous
in reply to: jeremytammik

 

Found this:

 

https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/CloudHelp/cloudhelp/2014/EN...

 

 

Which details how to call Revit buttons from the API, including Purge. It's a better solution than just telling the user to run Purge at the end of the plugin as it automatically calls up the box for them.

 

 

Limitations:

  • You can't call a button from half way through your plugin.
    • You have to set it up to run after your plugin is done.
    • You might be able to get around this with subscribing to the Executed event but I'll need to experiment with that.
  • You don't know whether the command will run successfully.
    • Also, as you can't run it half way through your program, you have no way of checking whether it's succeeded within code.
    • You can check the journal logs and parse the result of the latest command but that's a very hack-y feeling solution.
  • You don't know ahead of time whether someone else has overridden the button to do something else.
    • The call is to just press the button. The article above focuses on overriding buttons. You can't guarantee that the button still does what you're expecting it to.
  • The process you trigger by pressing the button cannot be automated.
    • Your script has to finish before the button is pressed so you can't take control of the resulting dialogs.
    • You may be able to subscribe to the button events and fiddle something that way. Again, experimentation needed.
Message 5 of 26
r.singleton
in reply to: Anonymous

While I am not a huge fan of the IdlingEvents, you can subscribe to one and put this to some more flexible use. From some testing, I've found that Revit doesn't seem to truly get the purge done fully until it has processed this command about 6 or 7 times. At least in our typical documents.

 

So I have a counter set up and after the PostableCommand has taken place 6 times, it unsubscribes from the idling event and resumes normal Revit behavior. Not sure if that helps, but since you are talking about it and I've worked on something similar, might as well toss those two pennies in.

Message 6 of 26
Anonymous
in reply to: r.singleton

Hi,

do you know how to send keys multiple times to purge unused rather than using the postable command? or something similar? also I am code blocking with a modal form is there any way to get around having to get a user close an annoying message box?

Message 7 of 26
jeremytammik
in reply to: Anonymous
Message 8 of 26
Anonymous
in reply to: Anonymous

Hi Thomas, Thanks for sharing the solution. I was struggling writing the purge code by myself. The solution you've shared looks interesting, would appreciate if you share a code snippet to call purge button from revit api code. Cheers

Tags (2)
Message 9 of 26
jeremytammik
in reply to: Anonymous

More details on the PostCommand functionality including some code samples is provided here:

 

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



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

Message 10 of 26
Anonymous
in reply to: Anonymous

I've come up with the solution, but the limitation I'm facing, I cant cable to run the revit command button instantly it runs at the end of the program. Here's the sample code that i've written. would appreciate if someone suggest how do I run revit command button instantly.

 

        UIApplication uiapp = commandData.Application;

        //Store the ID of desired plugin button, in this case its 'purge unused'
        String s_commandToDisable = "ID_PURGE_UNUSED";
        RevitCommandId s_commandId = RevitCommandId.LookupCommandId(s_commandToDisable);

        //This revit button will run at the end of your application. 
        uiapp.PostCommand(s_commandId);
Message 11 of 26
jeremytammik
in reply to: Anonymous

Yes. PostCommand launches a Revit command. The command cannot run in parallel with your add-in. Therefore, your add-in must terminate before the next command can run. You can add another PostCommand to call a second add-in command to be executed afterwards to continue the process.



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

Message 12 of 26
jeremytammik
in reply to: Anonymous

Edited and published the current solution using PostCommand here:

 

http://thebuildingcoder.typepad.com/blog/2017/11/purge-and-detecting-an-empty-view.html#2



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

Message 13 of 26

I have found an existing simple solution for this (for Revit 2017+). See my code repository:

https://gitlab.com/MattTaylor/RevitPurgeUnused


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
Message 14 of 26
Martin.Servold_MEE
in reply to: Anonymous

I've been trying to figure this out in spare time for the past couple months. Finally ran across this:

https://gitlab.com/MattTaylor/RevitPurgeUnused

and translated it to python. This is set up to purge 4 times in a row because we all know revit doesn't get it all in the first pass.

 

purgeGuid = 'e8c63650-70b7-435a-9010-ec97660c1bda'
purgableElementIds = []
performanceAdviser = DB.PerformanceAdviser.GetPerformanceAdviser()
guid = System.Guid(purgeGuid)
ruleId = None
allRuleIds = performanceAdviser.GetAllRuleIds()
for rule in allRuleIds:
# Finds the PerformanceAdviserRuleId for the purge command if str(rule.Guid) == purgeGuid: ruleId = rule ruleIds = List[DB.PerformanceAdviserRuleId]([ruleId]) for i in range(4):
# Executes the purge failureMessages = performanceAdviser.ExecuteRules(doc, ruleIds) if failureMessages.Count > 0:
# Retreives the elements purgableElementIds = failureMessages[0].GetFailingElements()
# Deletes the elements try: doc.Delete(purgableElementIds) except: for e in purgableElementIds: try: doc.Delete(e) except: pass

 

 

Message 15 of 26

Nice - see post directly above. Smiley Wink

Thanks for sharing.


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
Message 16 of 26
H.echeva
in reply to: matthew_taylor

Thank you very much for this solution. So far it is the best one that I could find.

Unfortunately, this doesn't work with materials and material assets (Jeremy kindly shared a solution for purging materials here). I assume that for deleting the material assets a similar approach would work, anyone has tried this?

 

Here is my working attempt as a C# application macro if someone needs it:

public void Purge()
		{
			//Note this won't purge materials
			
			UIDocument uidoc = this.ActiveUIDocument;
			Document doc = uidoc.Document;
			
			string desiredRule = "Project contains unused families and types";
			
			//access the Performance adviser
			PerformanceAdviser perfAdviser = PerformanceAdviser.GetPerformanceAdviser();
			
			//create a list with all the rules
			IList<PerformanceAdviserRuleId> allRulesList = perfAdviser.GetAllRuleIds();
			
			//create an empty list to save the rules that we want to run 
			//(in the purge case just one rule)
			IList<PerformanceAdviserRuleId> rulesToExecute = new List<PerformanceAdviserRuleId>();
			
			//Iterate through each
			foreach(PerformanceAdviserRuleId r in allRulesList)
			{
				if(perfAdviser.GetRuleName(r).Equals(desiredRule))
				{
					rulesToExecute.Add(r);
				}
			}
			for(int i=0;i<5;i++)
			{
				//execute the rules and get the results
				IList<FailureMessage> failureMessages = perfAdviser.ExecuteRules(doc,rulesToExecute);
				
				//Check if there are results
				if(failureMessages.Count()== 0) return;
				
				ICollection<ElementId> failingElementsIds = failureMessages[0].GetFailingElements();
				
				using(Transaction t = new Transaction(doc,"purge"))
				{
					t.Start();
					foreach(ElementId eid in failingElementsIds)
					{
						try
						{
							doc.Delete(eid);
						}
						catch
						{
	
						}
					}
					
					t.Commit();
				}	
			}
		}
Message 17 of 26
aricke59
in reply to: H.echeva

Thanks to all those that provided a solution for this. 

 

It is worth noting that NO Materials or Material Assets are addressed by this rule. Is anyone from Autodesk able to enlighten us as to why?

Message 18 of 26
jeremytammik
in reply to: aricke59

Does the purge command normally clean up materials and their assets?

 



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

Message 19 of 26
H.echeva
in reply to: jeremytammik

Hello Jeremy,

 

Yes, it does, after running it 3 times (sometimes more). The first time you run it, it cleans families but it leaves materials that are no longer in use. Then you run it a second time and I think it cleans those materials that then leave unused material assets. The third time it usually cleans the remaining assets.

This is why some people try to send the postcommand three times.

Regards.

Message 20 of 26
jeremytammik
in reply to: H.echeva

Next question: does the performance adviser perform the same functionality as the purge command?

 

Is it expected to do so?

 



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

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community