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();
Solved! Go to Solution.
Solved by guflerZD74K. Go to Solution.
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
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.