I have a FilteredElementCollector for sections (ViewSection). Can it be modified to get only sections that are not referenced? Thanks
var secIds = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .ToElementIds(); f.Refresh();
I don't know what referenced section means but you can search Revit Lookup for this. If that means section view depend on another view you can check the dependent views of the element. Here is the code snippet.
This collector collects if section view has no dependent view.
var viewSections = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .Cast<ViewSection>() .Where(q => q.GetDependentViewIds().Count == 0);
I hope this helps,
Recep.
Thanks for the reply. I may be using the wrong terminology. I'm trying to get Sections that are not on sheets.
Sorry, I misunderstood your question. Here is a code snippet that shows which building section views didn't add to sheets. You can restrict to the specified sheet to as you wish. I tried myself this code in Visual Studio 2019 and Revit 2020 and it worked.
// Collect all building section views
var sectionViews = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .Cast<ViewSection>() // This filter restrict the filter for only building sections. // You can obtain parameter and value from Revit LookUp. .Where(q => q.get_Parameter(BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM).AsValueString() == "Section: Building Section") .GetEnumerator(); // Collect all sheets var sheets = new FilteredElementCollector(doc) .OfClass(typeof(ViewSheet)) .Cast<ViewSheet>() .GetEnumerator(); while (sheets.MoveNext()) { var sheet = sheets.Current; foreach (var viewId in sheet.GetAllPlacedViews()) { var view = doc.GetElement(viewId) as View;
// Check if view is section view if (view.ViewType == ViewType.Section) { while (sectionViews.MoveNext()) { ViewSection sectionView = sectionViews.Current; // If views in sheet don't contain if (sectionView.Id != viewId) { TaskDialog.Show("Missing Section View", sectionView.Name + " isn't added"); }
// If sheet contains nothing if (viewId == null) TaskDialog.Show("Missing Section View", sectionView.Name + " isn't added"); } } } }
I hope this helps,
Recep.
Dear Bernie,
Thank you for your query, and many thanks to Recep for his very helpful answers.
I have a suggestion based on a slightly more abstract view of the task which may help implement a more optimised solution for both this and other purging tasks.
By the way, looking back at your original question: What is `f`, that you call `Refresh` on? I guess that does not matter?
I believe this can indeed be easily solved.
The trick is to find some characteristic feature to test on the ViewSection class that let us determine whether it is referenced or not, or how many references to it exist.
What is a reference to a section view, and where can it be determined?
Is it always a reference from a sheet view?
Can it always be determined by calling the ViewSheet GetAllPlacedViews method?
http://www.revitapidocs.com/2020/af2ee879-173d-df3a-9793-8d5750a17b49.htm
If so, then here is my suggestion:
The Revit API GetAllPlacedViews method defines a relationship mapping a ViewSheet to all views placed on it, including ViewSection objects.
This relationship can easily be inverted to map the ViewSection objects (or all placed views) to all ViewSheet objects referencing it.
I discussed a simple relationship inverter in one of the first blog posts, number 16, in 2008:
http://thebuildingcoder.typepad.com/blog/2008/10/relationship-in.html
It is maintained as part of The Building Coder samples, in the module CmdRelationshipInverter.cs.
Later, in 2009, The Building Coder also discussed the relationship between viewports and sheets:
http://thebuildingcoder.typepad.com/blog/2009/01/viewports-and-sheets.html
The discussion there and the command that it implements is too convoluted and gets into too much detail for me to understand fully right here and now. I am either too lazy, busy or obtuse. So, instead, I'll start again from scratch.
Implement map_sheet_to_placed_views like this:
To invert the relationship:
With that reverse relationship set up, you know that every placed view has an entry in map_placed_view_to_sheets pointing to the sheets it has been placed on.
An unplaced view has no such entry.
Therefore, you can simply add a post-processing step to the filtered element collector above to eliminate the placed views from the filter results and retain only unplaced views:
var secIds = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .ToElementIds() .Where<ElementId>( id => !map_placed_view_to_sheets.ContainsKey(id.IntegerValue) );
One big advantage of this approach is that you know exactly what you are doing, and that each step is performant:
I hope this helps.
Best regards,
Jeremy
Thanks for the reply Jeremy, The "f' that I'm refreshing is a progress dialog. Something so the user doesn't think it's stalled. I'm attempting to delete various kinds of user selected (checkBox) annotations from all views. Here's the Section portion of the code.
// Sections void DeleteSections(Document doc) { ProcessingForm f = new ProcessingForm(); f.lblProcessing.Text = "Deleting sections... "; f.Show(); f.Refresh(); var secIds = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .ToElementIds(); f.Refresh(); foreach (var sec_id in secIds) { try { doc.Delete(sec_id); secCount++; } catch { f.Refresh(); f.lblProcessing.Text = "Deleting sections... " + secCount.ToString() + " deleted."; f.Refresh(); } } f.Close(); }
You can probably speed it up significantly by not deleting the sections one at a time, but all at once, in one single call to Delete, passing in the whole list of element ids.
Looking forward to hearing how it goes with the filtered retrieval of unplaced section views!
Hi Jeremy,
I'm getting some errors when I use the snipit you sent me. I've added two attachments. Thanks for the help!
// Sections void DeleteSections(Document doc) { ProcessingForm f = new ProcessingForm(); f.lblProcessing.Text = "Deleting sections... "; f.Show(); f.Refresh(); var secIds = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .ToElementIds() .Where<ElementId>(id => !map_placed_view_to_sheets.ContainsKey(id.IntegerValue)); f.Refresh(); foreach (var sec_id in secIds) { try { doc.Delete(sec_id); secCount++; } catch { f.Refresh(); f.lblProcessing.Text = "Deleting sections... " + secCount.ToString() + " deleted."; f.Refresh(); } } f.Close(); }
Dear Bernie,
Thank you for your update.
Yes, of course.
I provided instructions explaining how to:
I tried to explain exactly how to achieve that. The blog post on inverting a relationship explains the second step, and the first is really trivial.
If you have not implemented those two steps, these dictionaries will not exist.
Best regards,
Jeremy
Thanks Jeremy,
I'm not sure I understand how to do that but will investigate further. Thanks for pointing me in the right direction.