Deleting unpurgeable viewport types through API

Deleting unpurgeable viewport types through API

pieterschiettecatte
Advisor Advisor
5,582 Views
17 Replies
Message 1 of 18

Deleting unpurgeable viewport types through API

pieterschiettecatte
Advisor
Advisor

When you copy views (including schedules) from one project to another, it brings in the default viewport type of that project. That viewport type becomes unpurgeable. So if you do this with enough files, you get a whole bunch of unpurgeable viewport types in your project.

 

We have a few of these unpurgeable viewport types in our template and I'm looking for a way to clean this up without being forced to recreate the template, which would take me weeks.

 

Anyone any ideas on how I could achieve this through the API (if possible at all)?

0 Likes
Accepted solutions (1)
5,583 Views
17 Replies
Replies (17)
Message 2 of 18

jeremytammik
Autodesk
Autodesk
Accepted solution

Dear Pieter,

 

Thank you for your query.

 

In general, you can delete any database element using the Document.Delete method:

 

http://www.revitapidocs.com/2019/dd023de2-cf2b-03ca-6f45-89b5e867fe92.htm

 

Have you tried using that on the viewport types you want to get rid of?

 

You should be able to determine their element ids somehow, e.g., using RevitLookup or other means, and then hard-code them into a call to Document.Delete.

 

What happens if you do so?

 

Best regards,

 

Jeremy

 



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

Message 3 of 18

pieterschiettecatte
Advisor
Advisor

It worked.

 

Can't believe it was that simple. 

 

For anyone coming across this topic through google:

 

  • First, find the viewport Type ID using Revit Lookup
    • assign viewport you want to delete to a view on a sheet
    • select the viewport
    • use 'snoop current selection'
    • doubleclik GetTypeId
    • copy the id
  • You can use dynamo to do the deleting. See screenshot of the graph:

 

dynamo delete viewport.JPG

 

Two big warnings though: 

  • if you have views placed on sheets using that viewport, they will be deleted from the sheet (to be expected I guess)
  • however, this one is a lot trickier: if you have schedules using that viewtype, they will be deleted from the file. Yes, from the file, not just from the sheet. And you might ask: I thought schedules don't have viewports ... I would say ... yes that's what I thought as well...

@jeremytammik  do you have any suggestions on how to prevent this last issue? I have no idea how to change the viewport of a schedule? I can't even find a reference to it in RevitLookup. It seems other users have reported the same unexpected behavior as well: https://forums.autodesk.com/t5/revit-api-forum/unused-revit-system-viewports/td-p/7176217

 

My theory is this: when you transfer schedules, sheets etc from other files you also bring in the default viewport of that file. It seems that that viewport is forever 'attached' to those schedules/sheets now. When you use the API to delete these elements, it also deleted the schedules/sheets you initially brought over.

 

 

Message 4 of 18

pieterschiettecatte
Advisor
Advisor

Wait a minute.

 

The problem is not just limited to schedules. It happens to all viewtypes.

 

For example: I brought in some drafting views from another model, which triggered the creation of an extra viewport type.

 

I put those drafting views on a sheet, changed the viewport type to my desired one, and then ran the dynamo script to get rid of the old viewport. All the imported drafting views were deleted from the file, although as far as I can see in RevitLookup, they no longer have a connection to that viewport type.

0 Likes
Message 5 of 18

jeremytammik
Autodesk
Autodesk

Congratulations on the simple solution and sorry to hear about the serious complications.

 

One thing you definitely ought to monitor is the return value of the call to Delete.

 

It is a list of all element ids that were deleted.

 

If you want to avoid deleting other object (unexpectedly?), you should ensure that the list only contains one element, the id of the thing you want to delete.

 

Maybe the GetDependentElements also returns those additional element ids with no need to call Delete?

 

https://thebuildingcoder.typepad.com/blog/2019/03/retrieving-and-snooping-dependent-elements.html

 

Unfortunately, I have no idea how to clean up those unwanted dependencies before deleting the unwanted elements.

 

Maybe the viewport type does not contain any reference to the schedule, but only vice versa: does the schedule contain a reference to the viewport type? 

  

Cheers,

  

Jeremy

  



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

0 Likes
Message 6 of 18

jeremytammik
Autodesk
Autodesk

Unfortunately, the ViewSchedule ViewType property is read-only:

 

http://www.revitapidocs.com/2019/76bee86d-3c34-7ee1-4349-cd7abcbf3d78.htm

 



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

0 Likes
Message 7 of 18

pieterschiettecatte
Advisor
Advisor

Hey Jeremy,

 

It's weird. It's not just the schedule viewtype. It seems to apply to all type of views.

 

When I purge the unwanted viewport types from my template, I lose about half of my views (a few hundreds details and schedules). I think all of the views were at some point transferred from other projects (or are duplicates of views that were). 

 

None of these views are using the deleted viewport types though. And as far as I can tell, Revit Lookup doesn't show any relationships what so ever between the deleted viewports, and the views that are deleted with it.

 

I'm a bit confused by it really.

0 Likes
Message 8 of 18

pieterschiettecatte
Advisor
Advisor

Update for everyone who's interested in this topic: PyRevit has a tool that makes the unpurgeable viewports purgeable. Not sure how they do it, but their code is on github.

 

Also, their approach doesn't have the side-effects of deleting views/schedules. 

Message 9 of 18

bsulliv
Contributor
Contributor

This absolutely works! I employed the "get all viewport types" block -> list create - > Element name. Pinned the output so that I can see which elements id's to type into the code block.

Well done!

0 Likes
Message 10 of 18

Sean_Page
Collaborator
Collaborator

I am not sure why it happens, but I ran into this and wanted to figure it out and I was moving views from several old files into one and it was brining all kinds of junk with it.  Here is the solution I came up with, however I am not sure why the Viewport Type retains dependency on the Views even through the VP Type was changed in the UI, but you have to complete a ChangeTypeId() on the Viewports to make it stick.

 

Dependent Elements_2021-09-17_01-24-23.png

Embeded Viewport Type | Revit | Autodesk Knowledge Network

Sean Page, AIA, NCARB, LEED AP
Senior Partner, Computational Designer, Architect
0 Likes
Message 11 of 18

curtisridenour
Advisor
Advisor

This is to add on to the script from above. I needed to know which was the correct viewports to delete. Seems to work just fine. But it is a manual process to type in the ID number.

curtisridenour_0-1640124627435.png

Thank You @pieterschiettecatte for the simple solution.

0 Likes
Message 12 of 18

priscillia_champagne
Contributor
Contributor

For some reason, when I try to run this function with pyRevit, no viewports come up, although I do have a few in my project. Would you happen to know why ? 

0 Likes
Message 13 of 18

KEVIN_W_MAK_WSP
Participant
Participant

PyRevit did the trick by swapping the unpurgeable from one type to another. Does anyone know what the exact problem is? What is depending on that unpurgeable viewport type and what need to be done in the API? Thanks!

0 Likes
Message 14 of 18

Moustafa_K
Advisor
Advisor

I've been studying the pyRevit code for purging viewports, and it's intriguing how the developer approached the task. It seems their aim was to gather a collection of all viewport types from the document. However, identifying viewport types directly posed a challenge because they lack a defined category or specific class. Instead, they are categorized under the ElementType class, which serves as a base class for all element types in Revit.

 

To overcome this obstacle, pyRevit implemented a try-catch mechanism. By attempting to switch a viewport instance type to another type, they could determine if it belonged to the category of viewport types. Once pyRevit collected these types, it filtered out the viewport instance type IDs from the potentially purgable IDs and proceeded to delete them.

 

Considering alternative approaches, one could explore the possibility of identifying purgable viewports indirectly by targeting existing parameters. For example, since ViewportType is a system family and all must possess the "Show Extension Line" parameter (BuiltInParameter.VIEWPORT_ATTR_SHOW_EXTENSION_LINE), we can use this parameter as a filter rule to identify all types that possess it. Fortunatly, this parameter is a bool parameter, which its value is either 0 or 1, then we can use (ParameterFilterRuleFactory.CreateGreaterOrEqualRule) and supply a value 0 for checking. 

 

With a list of viewport types established, the next step involves iterating through each type to retrieve the associated viewports using the GetDependentElements(ElementFilter) method.

Here's an example to illustrate the process:

 

// create filterRule to be used in collection
var rule = ParameterFilterRuleFactory.CreateGreaterOrEqualRule(
                    new ElementId(BuiltInParameter.VIEWPORT_ATTR_SHOW_EXTENSION_LINE),0
);

// get all elements that comply to this rule
var viewPortTypes = new FilteredElementCollector(doc)
	.WhereElementIsElementType()
	.OfCategory(BuiltInCategory.INVALID)
	.WherePasses(new ElementParameterFilter(rule));

// now for each viewportType find a viewport instance dependent
List<ElementId> purgeableIds = new List<ElementId>();
foreach (var viewportType in viewPortTypes)
{
	var viewports = viewportType.GetDependentElements(
		new ElementCategoryFilter(BuiltInCategory.OST_Viewports)
	);
	if (!viewports.Any())
	{
		purgeableIds.Add(viewportType.Id);
	}
}

// show a list of all purgeable Ids
MessageBox.Show(
string.Join("\r\n", purgeableIds.Select(o => o.Value.ToString()))
);
// ... handle these ids

 

 I just tested it on 2025, would be glad to know if there are some holes in this method.

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
Message 15 of 18

KEVIN_W_MAK_WSP
Participant
Participant

Your code works on my end; it allows me to get all purgeable viewport types in the project. I can use the reverse logic to get all unpurgeable and get their dependent element Id's.

And thanks for sharing the path to the pyRevit purge viewport code. This is going to be a great help too!

0 Likes
Message 16 of 18

Moustafa_K
Advisor
Advisor

so glad it helps 🙂 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 17 of 18

Sean_Page
Collaborator
Collaborator

Here is what I use to get Viewport Types. It may not be super language stable, but it works great for me.

 

FilterRule rule = ParameterFilterRuleFactory.CreateEqualsRule(new ElementId((Int64)BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM), "Viewport");
ElementParameterFilter filter = new ElementParameterFilter(rule);
IList<ElementType> viewportTypes;
using(FilteredElementCollector fec = new FilteredElementCollector(doc).OfClass(typeof(ElementType)).WherePasses(filter))
{
	viewportTypes = fec.Cast<ElementType>().ToList();
}
return viewportTypes;
Sean Page, AIA, NCARB, LEED AP
Senior Partner, Computational Designer, Architect
Message 18 of 18

Admin.CTI
Contributor
Contributor

I have the problem that when i remove some of the viewports, other stuff gets removed, such as Sheets or legends, even when before the removal i reassigned every view to a valid viewport not to be removed. Anyone have a solution for this?

0 Likes