RoleProvider - RoleCustomTypeDescriptor
In the last post about our RoleProvider I outlined the RolePropertyDescriptor, which is a class that describes the custom properties our class will have (representing the roles a user might belong to).
This post is about the RoleCustomTypeDescriptor, which is the class that tells the framework which "role properties" belong to the instance of RoleProvider it's looking at.
So if you have instantiated a RoleProvider and added a role to it called "DepartmentManagers", you want the binding framework to see a "DepartmentManagers" property on that object, of type "bool".
And here's the code!
public class RoleCustomTypeDescriptor : CustomTypeDescriptor { public RoleCustomTypeDescriptor(ICustomTypeDescriptor parent, object instance) : base(parent) { _instance = instance as RoleProvider; } private RoleProvider _instance; public override PropertyDescriptorCollection GetProperties() { return GetProperties(null); } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { PropertyDescriptorCollection props = base.GetProperties(attributes); List<PropertyDescriptor> allProperties = new List<PropertyDescriptor>(); foreach (PropertyDescriptor prop in props) { allProperties.Add(prop); } foreach (string key in _instance.Roles.Keys) { PropertyDescriptor kpd = new RolePropertyDescriptor(key); allProperties.Add(kpd); } return new PropertyDescriptorCollection(allProperties.ToArray()); } }
So our custom type descriptor takes the instance in question as part of its constructor, and caches it away in its "_instance" private field. It then overrides the "GetProperties" methods, and it's in there that we add a new property for each defined role to that particular instance of the class.
You'll notice that I've overrided both versions of GetProperties. This is the trick to making this work in both Windows Forms and WPF. WinForms' data binding engine looks for the version of GetProperties that takes an "attributes" parameter. WPF's looks for the version that takes no parameters. You need to override both if you want this class to work in both frameworks.