public PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes, bool noFilter) {
if (this.properties == null) {
this.properties = new PropertyDescriptorCollection(new MemberList(this).GetProperties(), true);
}
// We will use this to reconstruct the set of properties in case we have extenders, etc.
//
ArrayList allProps = null;
PropertyStash propStash = null;
bool inDictionary = false;
// This will be what we finally return. we default to the current static set of
// properties.
//
PropertyDescriptorCollection filteredProperties = properties;
if (component is IComponent) {
ISite site = ((IComponent)component).Site;
IExtenderProvider[] providers;
if (site != null) {
providers = GetExtenderProviders(site);
}
else {
providers = null;
}
ITypeDescriptorFilterService tf = null;
if (!noFilter)
tf = (ITypeDescriptorFilterService)GetService(component, typeof(ITypeDescriptorFilterService));
// First, check to see if we found the properties in the dictionary service. If so, we
// can fall out immediately because we have already stashed them.
//
IDictionaryService ds = (IDictionaryService)GetService(component, typeof(IDictionaryService));
if (ds != null) {
object filterStash = null;
lock(ds) {
propStash = (PropertyStash)ds.GetValue(typeof(PropertyStash));
filterStash = ds.GetValue(typeof(ITypeDescriptorFilterService));
}
// Check that the filter that was used to create these attributes is the same
// filter we currently have. People may replace the filter, and if we do
// we must refresh the cache.
//
if ((filterStash == null || filterStash == tf) && propStash != null && propStash.ExtendersMatch(providers, component)) {
// Now check to see if the stashed array of attributes also matches. If
// it does, then we can return a stashed pre-filtered set of props.
//
if (propStash.AttributesMatch(attributes)) {
filteredProperties = propStash.FilteredProperties;
attributes = null;
}
else {
allProps = propStash.Properties;
}
inDictionary = true;
}
}
// Now check to see if the container wants to filter the set of properties.
//
if (!inDictionary) {
if (providers != null && providers.Length > 0) {
ICollection extendedProperties = GetExtendedProperties((IComponent)component, providers);
if (extendedProperties != null && extendedProperties.Count > 0) {
allProps = new ArrayList(properties.Count + extendedProperties.Count);
allProps.AddRange(properties);
allProps.AddRange(extendedProperties);
}
}
if (tf != null) {
Hashtable filterTable = new Hashtable(properties.Count);
if (allProps == null) {
allProps = new ArrayList(properties);
}
foreach (PropertyDescriptor p in allProps) {
// We must handle the case of duplicate property names
// because extender providers can provide any arbitrary
// name. Our rule for this is simple: If we find a
// duplicate name, resolve it back to the extender
// provider that offered it and append "_" + the
// provider name. If the provider has no name,
// then append the object hash code.
//
if (filterTable.Contains(p.Name)) {
// First, handle the new property. Because
// of the order in which we added extended
// properties above, we can be sure that
// the new property is an extender. We
// cannot be sure that the existing property
// in the table is an extender, so we will
// have to check.
//
string suffix = GetExtenderCollisionSuffix(p);
Debug.Assert(suffix != null, "Name collision with non-extender property.");
if (suffix != null) {
filterTable[p.Name + suffix] = p;
}
// Now, handle the original property.
//
PropertyDescriptor origProp = (PropertyDescriptor)filterTable[p.Name];
suffix = GetExtenderCollisionSuffix(origProp);
if (suffix != null) {
filterTable.Remove(p.Name);
filterTable[origProp.Name + suffix] = origProp;
}
}
else {
filterTable[p.Name] = p;
}
}
bool cache = tf.FilterProperties((IComponent)component, filterTable);
allProps = new ArrayList(filterTable.Values);
if (ds != null && cache) {
propStash = new PropertyStash(allProps, providers, component);
lock(ds) {
ds.SetValue(typeof(PropertyStash), propStash);
ds.SetValue(typeof(ITypeDescriptorFilterService), tf);
}
inDictionary = true;
}
}
}
}
if (attributes != null && attributes.Length > 0) {
if (allProps == null) {
allProps = new ArrayList(properties);
}
else if (inDictionary) {
// If we just poked this into the dictionary, we must clone. Otherwise
// we will disrupt the dictionary.
//
allProps = new ArrayList(allProps);
inDictionary = false;
}
FilterMembers(typeof(PropertyDescriptor), allProps, attributes);
}
if (allProps != null) {
PropertyDescriptor[] temp = new PropertyDescriptor[allProps.Count];
allProps.CopyTo(temp, 0);
filteredProperties = new PropertyDescriptorCollection(temp, true);
if (propStash != null) {
propStash.FilteredProperties = filteredProperties;
propStash.Attributes = attributes;
}
}
return filteredProperties;
}