Search code examples
c#viewelementrevit-apirevit

Determine is a FamilyInstance is visible in a View


I have a FamilyInstance pFam and a Autodesk.Revit.DB.View pView. I want to know if pFam is visible in pView. I've tried using

if (pFam.IsHidden(pView)
    continue;

Unfortunately, this only tells me if the element is supposed to be hidden, which isn't the case. But, the element is not visible in every View, and under that circumstance, I want (or rather don't want) something to happen. There is no Visible or IsVisible properties for FamilyInstances... Does anyone know a way to handle these situations?

Thanks!


Solution

  • I have found that the most reliable way of knowing whether an element is visible in a view is to use a FilteredElementCollector specific to that view. There are so many different ways of controlling the visibility of an element that it would be impractical to try to determine this any other way.

    Below is the utility function I use to achieve this. Note this works for any element, and not just for family instances.

    public static bool IsElementVisibleInView([NotNull] this View view, [NotNull] Element el)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }
    
            if (el == null)
            {
                throw new ArgumentNullException(nameof(el));
            }
    
            // Obtain the element's document
            Document doc = el.Document;
    
            ElementId elId = el.Id;
    
            // Create a FilterRule that searches for an element matching the given Id
            FilterRule idRule = ParameterFilterRuleFactory.CreateEqualsRule(new ElementId(BuiltInParameter.ID_PARAM), elId);
            var idFilter = new ElementParameterFilter(idRule);
    
            // Use an ElementCategoryFilter to speed up the search, as ElementParameterFilter is a slow filter
            Category cat = el.Category;
            var catFilter = new ElementCategoryFilter(cat.Id);
    
            // Use the constructor of FilteredElementCollector that accepts a view id as a parameter to only search that view
            // Also use the WhereElementIsNotElementType filter to eliminate element types
            FilteredElementCollector collector =
                new FilteredElementCollector(doc, view.Id).WhereElementIsNotElementType().WherePasses(catFilter).WherePasses(idFilter);
    
            // If the collector contains any items, then we know that the element is visible in the given view
            return collector.Any();
        }
    

    The category filter is used to eliminate any element not of the desired category before using the slower parameter filter to find the desired element. It is probably possible to speed this up further with clever usage of filters, but I have found that it is plenty fast enough for me in practice.

    If you don't have ReSharper, delete the [NotNull] annotations you see.