diff --git a/sources/editor/Stride.Assets.Presentation/NodePresenters/Keys/EntityHierarchyData.cs b/sources/editor/Stride.Assets.Presentation/NodePresenters/Keys/EntityHierarchyData.cs index 9c822e3e61..a188d2635b 100644 --- a/sources/editor/Stride.Assets.Presentation/NodePresenters/Keys/EntityHierarchyData.cs +++ b/sources/editor/Stride.Assets.Presentation/NodePresenters/Keys/EntityHierarchyData.cs @@ -12,10 +12,9 @@ namespace Stride.Assets.Presentation.NodePresenters.Keys public static class EntityHierarchyData { public const string EntityComponentAvailableTypes = nameof(EntityComponentAvailableTypes); - public static readonly PropertyKey> EntityComponentAvailableTypesKey = new PropertyKey>(EntityComponentAvailableTypes, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperty)); - + public static readonly PropertyKey> EntityComponentAvailableTypesKey = new PropertyKey>(EntityComponentAvailableTypes, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperties)); public const string EntityComponentAvailableTypeGroups = nameof(EntityComponentAvailableTypeGroups); - public static readonly PropertyKey> EntityComponentAvailableTypeGroupsKey = new PropertyKey>(EntityComponentAvailableTypeGroups, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperty)); + public static readonly PropertyKey> EntityComponentAvailableTypeGroupsKey = new PropertyKey>(EntityComponentAvailableTypeGroups, typeof(EntityHierarchyData), new PropertyCombinerMetadata(AbstractNodeEntryData.CombineProperties)); } } diff --git a/sources/editor/Stride.Core.Assets.Editor/Quantum/NodePresenters/Keys/AbstractNodeEntryData.cs b/sources/editor/Stride.Core.Assets.Editor/Quantum/NodePresenters/Keys/AbstractNodeEntryData.cs index ed635bec66..a51a689b1f 100644 --- a/sources/editor/Stride.Core.Assets.Editor/Quantum/NodePresenters/Keys/AbstractNodeEntryData.cs +++ b/sources/editor/Stride.Core.Assets.Editor/Quantum/NodePresenters/Keys/AbstractNodeEntryData.cs @@ -10,11 +10,12 @@ namespace Stride.Core.Assets.Editor.Quantum.NodePresenters.Keys public static class AbstractNodeEntryData { public const string AbstractNodeMatchingEntries = nameof(AbstractNodeMatchingEntries); - public static readonly PropertyKey> Key = new PropertyKey>(AbstractNodeMatchingEntries, typeof(AbstractNodeEntryData), new PropertyCombinerMetadata(CombineProperty)); - + public static readonly PropertyKey> Key = new PropertyKey>(AbstractNodeMatchingEntries, typeof(AbstractNodeEntryData), new PropertyCombinerMetadata(CombineProperties)); + + [Obsolete("Use the generic version of CombineProperties instead, which allows to specify the type of the properties to combine. This method is kept for backward compatibility, but it is recommended to use the generic version instead.")] public static object CombineProperty(IEnumerable properties) { - var result = new HashSet(); + HashSet result; var hashSets = new List>(); hashSets.AddRange(properties.Cast>().Select(x => new HashSet(x))); result = hashSets[0]; @@ -25,5 +26,29 @@ public static object CombineProperty(IEnumerable properties) } return result.OrderBy(x => x.Order).ThenBy(x => x.DisplayValue); } + + /// + /// Combines the properties of type by intersecting them and ordering them by their order and display value. + /// This method allows to specify the type of the properties to combine, which can be useful when the properties are of a more specific type than . + /// E.g. WPF cannot coerce IEnumerable<AbstractNodeEntry> into IEnumerable<AbstractNodeType> since covariance only goes the other direction — you can widen to AbstractNodeEntry, not narrow back to AbstractNodeType. + /// In those cases, the binding would silently fall back to the DependencyProperty's default value: null. + /// + /// + /// + /// + public static IEnumerable CombineProperties(IEnumerable properties) + where TAbstractNodeEntry : AbstractNodeEntry + { + HashSet result; + var hashSets = new List>(); + hashSets.AddRange(properties.Cast>().Select(x => new HashSet(x))); + result = hashSets[0]; + // We display only component types that are available for all entities + for (var i = 1; i < hashSets.Count; ++i) + { + result.IntersectWith(hashSets[i]); + } + return result.OrderBy(x => x.Order).ThenBy(x => x.DisplayValue); + } } }