Announcements
Due to scheduled maintenance, the Autodesk Community will be inaccessible from 10:00PM PDT on Oct 16th for approximately 1 hour. We appreciate your patience during this time.
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: 

Use FilteredElementCollector to get FamilyInstances with specified host

2 REPLIES 2
SOLVED
Reply
Message 1 of 3
guflerZD74K
335 Views, 2 Replies

Use FilteredElementCollector to get FamilyInstances with specified host

Hi, I have a method that gives me all FamilyInstances that are hostet by the given element.

 

I was wondering if it is possible to achieve that by only using Revits Element filters, since my current implementation is slowing down my application.

 

 

 

 

public List<FamilyInstance> FamilyInstancesWithElementAsHost(Element element)
{
    return new FilteredElementCollector(element.Document).OfClass(typeof(FamilyInstance))
                                                         .Cast<FamilyInstance>()
                                                         .Where(fi => fi.Host != null && fi.Host.Id.IntegerValue == element.Id.IntegerValue)
                                                         .ToList();
}

 

 

 

 

I tried it like this, but it looks this parameter is always set to "-1":

 

 

 

BuiltInParameter bip = BuiltInParameter.HOST_ID_PARAM;


FilterableValueProvider filterableValueProvider = new ParameterValueProvider(new ElementId(bip));
FilterNumericRuleEvaluator filterNumericRuleEvaluator = new FilterNumericEquals();

FilterRule filterRule = new FilterElementIdRule(filterableValueProvider, filterNumericRuleEvaluator, element.Id);

ElementFilter elementFilter = new ElementParameterFilter(filterRule);

var betterVersion = new FilteredElementCollector(element.Document)
    .OfClass(typeof(FamilyInstance))
    .WherePasses(elementFilter)
    .ToList();

 

 

 

 

2 REPLIES 2
Message 2 of 3
Yien_Chao
in reply to: guflerZD74K

hi

 

if i understand , you can also use GetDependentElements() with the selected host.

but you will need a elementfilter (use ElementClassFilter(FamilyInstance) in your case)

 

ex : 

EF = ElementClassFilter(FamilyInstance)
ID = host.GetDependentElements(EF)

els = [doc.GetElement(i) for i in ID]
OUT = els

 

Message 3 of 3
guflerZD74K
in reply to: Yien_Chao

Unfortunately, this method does not contain the elements that are hosted by the element.

 

element.GetDependentElements(...)

 

However, I found another way to optimize this method. Since I do not modify the Revit project, I can just cache all Ids of the families that are hosted, together with the host id. This way I only have to make this call once (I will still need to re-create the cache per external call)

 

Here is an extension method I use to make this as simple as possible:

 

/// <summary>
/// Groups the given collection of <typeparamref name="TInput"/> based on a key and a value to get from each <typeparamref name="TInput"/>
/// </summary>
/// <returns>
/// A <see cref="Dictionary{TKey, TValue}"/> created from an <see cref="IEnumerable{T}"/> according to a specified key and value selector function
/// </returns> 
/// <typeparam name="TInput"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="input">a collection of <typeparamref name="TInput"/> to create a <see cref="Dictionary{TKey, TValue}"/> from</param>
/// <param name="func">logic to extract key and value for each <typeparamref name="TInput"/></param>
/// <param name="comparer">an optional comparer object to determine equality for the dictionary</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException"></exception>
public static Dictionary<TKey, IList<TValue>> ToMultiDictionary<TInput, TKey, TValue>(this IEnumerable<TInput> input, Func<TInput, (TKey, TValue)> func, IEqualityComparer<TKey> comparer = null)
{
    //all arguments have to be provided
    if (input is null)
        throw new ArgumentNullException(nameof(input) + " was null!");

    if (func is null)
        throw new ArgumentNullException(nameof(func) + " was null!");

    var dictionary = new Dictionary<TKey, IList<TValue>>(comparer);

    foreach (var item in input)
    {
        var (key, value) = func(item);

        //add to key, or create key and add
        if (dictionary.TryGetValue(key, out var list))
        {
            list.Add(value);
        }
        else
        {
            list = new List<TValue>()
            {
                value
            };
            dictionary[key] = list;
        }
    }

    return dictionary;
}

 

I use it like this:

 

Dictionary<int, IList<int>> grouped = familyInstancesInProject.ToMultiDictionary(x => ((x as FamilyInstance).Host?.Id.IntegerValue ?? -1, x.Id.IntegerValue));

//remove instances with no host
if (grouped.ContainsKey(-1))
    _ = grouped.Remove(-1);

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

Post to forums  

Rail Community


Autodesk Design & Make Report