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
318 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  

Forma Design Contest


Rail Community