//===================================================================== /// <summary> /// This is used to recursively add all child properties up to three levels down on reference type /// properties to the property collection. /// </summary> /// <param name="parentProp">The parent property descriptor</param> /// <param name="baseName">The base name used as a prefix for child property names</param> /// <param name="filter">The attribute filter, if any</param> /// <param name="props">The properties to search</param> /// <param name="newProps">The list to which new child properties are added</param> /// <remarks>To prevent endless recursion and stack overflows, it will only go down three levels. /// Properties with a <see cref="BrowsableAttribute"/> set to false are ignored. Properties with a /// <see cref="HidePropertyAttribute"/> are not added to the collection but their children are added.</remarks> private void GetChildProperties(PropertyDescriptor parentProp, string baseName, Attribute[] filter, PropertyDescriptorCollection props, List<PropertyDescriptor> newProps) { PropertyDescriptorCollection childProps, otherChildren; PropertyDescriptor parent; BrowsableAttribute browsable; string rootName, childName; // Don't go too far down or we could get stuck in an endless loop on properties that contain // instances of themselves. if(nestingLevel > 2) return; try { nestingLevel++; foreach(PropertyDescriptor pd in props) if(!pd.PropertyType.IsPrimitive && pd.PropertyType != typeof(string)) { // If it's not browsable, ignore it. We shouldn't have to do this but the initial // collection from GetProperties() (see below) seems to ignore the filter. browsable = (BrowsableAttribute)pd.Attributes[typeof(BrowsableAttribute)]; if(browsable != null && !browsable.Browsable) continue; // The browsable filter does work here though childProps = pd.GetChildProperties(filter); // Each child property will be prefixed with the parent property's name separated by an // underscore. We can't use a period as certain list controls such as ListBox and // ComboBox use the period as a binding path separator. rootName = baseName + pd.Name + "_"; foreach(PropertyDescriptor child in childProps) { childName = rootName + child.Name; // If this is a top-level property, the current property descriptor is used. If it's // a child, we need to wrap it in a ChildPropertyDescriptor. if(parentProp == null) parent = pd; else parent = new ChildPropertyDescriptor(parentProp, pd, rootName); // If hidden, don't add it to the visible properties but do include its children if(child.Attributes[typeof(HidePropertyAttribute)] == null) newProps.Add(new ChildPropertyDescriptor(parent, child, childName)); // Get all children of this child property otherChildren = child.GetChildProperties(filter); if(otherChildren.Count > 0) this.GetChildProperties(parent, rootName, filter, otherChildren, newProps); } } } finally { nestingLevel--; } }
//===================================================================== /// <summary> /// This is used to recursively add all child properties up to three levels down on reference type /// properties to the property collection. /// </summary> /// <param name="parentProp">The parent property descriptor</param> /// <param name="baseName">The base name used as a prefix for child property names</param> /// <param name="filter">The attribute filter, if any</param> /// <param name="props">The properties to search</param> /// <param name="newProps">The list to which new child properties are added</param> /// <remarks>To prevent endless recursion and stack overflows, it will only go down three levels. /// Properties with a <see cref="BrowsableAttribute"/> set to false are ignored. Properties with a /// <see cref="HidePropertyAttribute"/> are not added to the collection but their children are added.</remarks> private void GetChildProperties(PropertyDescriptor parentProp, string baseName, Attribute[] filter, PropertyDescriptorCollection props, List <PropertyDescriptor> newProps) { PropertyDescriptorCollection childProps, otherChildren; PropertyDescriptor parent; BrowsableAttribute browsable; string rootName, childName; // Don't go too far down or we could get stuck in an endless loop on properties that contain // instances of themselves. if (nestingLevel > 2) { return; } try { nestingLevel++; foreach (PropertyDescriptor pd in props) { if (!pd.PropertyType.IsPrimitive && pd.PropertyType != typeof(string)) { // If it's not browsable, ignore it. We shouldn't have to do this but the initial // collection from GetProperties() (see below) seems to ignore the filter. browsable = (BrowsableAttribute)pd.Attributes[typeof(BrowsableAttribute)]; if (browsable != null && !browsable.Browsable) { continue; } // The browsable filter does work here though childProps = pd.GetChildProperties(filter); // Each child property will be prefixed with the parent property's name separated by an // underscore. We can't use a period as certain list controls such as ListBox and // ComboBox use the period as a binding path separator. rootName = baseName + pd.Name + "_"; foreach (PropertyDescriptor child in childProps) { childName = rootName + child.Name; // If this is a top-level property, the current property descriptor is used. If it's // a child, we need to wrap it in a ChildPropertyDescriptor. if (parentProp == null) { parent = pd; } else { parent = new ChildPropertyDescriptor(parentProp, pd, rootName); } // If hidden, don't add it to the visible properties but do include its children if (child.Attributes[typeof(HidePropertyAttribute)] == null) { newProps.Add(new ChildPropertyDescriptor(parent, child, childName)); } // Get all children of this child property otherChildren = child.GetChildProperties(filter); if (otherChildren.Count > 0) { this.GetChildProperties(parent, rootName, filter, otherChildren, newProps); } } } } } finally { nestingLevel--; } }