using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LLVM.ClangTidy { /// /// The goal of this class is to enable displaying of a PropertyGrid in much the /// same way that Visual Studio's C++ project system does. A project or file can /// have properties which might inherit from their parent, or be overridden. /// It turns out this is somewhat non-trivial. The .NET PropertyGrid is good makes /// displaying simple properties with a static notion of what constitutes a /// "default" value very easy. You simply apply an Attribute to the class that says /// what the default value is and you're done. But when you try to introduce the idea /// that a property's default value depends on some other factor, things get much more /// complicated due to the static nature of Attributes. /// /// The solution to this is to inherit from ICustomTypeDescriptor. This is the mechanism /// by which you can inject or modify attributes or properties at runtime. The .NET /// PropertyGrid is designed in such a way that instead of using simple .NET Reflection to /// look for the properties and attributes on a class, it will invoke the methods of /// ICustomTypeDescriptor (if your type inherits from it), and ask those methods. Our /// implementation of ICustomTypeDescriptor works by waiting until the PropertyGrid requests /// PropertyDescriptors for each of the properties, and then "decorating" them with our /// own custom PropertyDescriptor implementation which understands the proeprty inheritance /// model we wish to implement. /// public partial class DynamicPropertyComponent : Component, ICustomTypeDescriptor { PropertyDescriptorCollection DynamicProperties_ = new PropertyDescriptorCollection(null); private DynamicPropertyComponent Parent_; public DynamicPropertyComponent(DynamicPropertyComponent Parent) { Parent_ = Parent; } public DynamicPropertyComponent(DynamicPropertyComponent Parent, IContainer container) { Parent_ = Parent; container.Add(this); InitializeComponent(); } public AttributeCollection GetAttributes() { return TypeDescriptor.GetAttributes(GetType()); } public string GetClassName() { return TypeDescriptor.GetClassName(GetType()); } public string GetComponentName() { return TypeDescriptor.GetComponentName(GetType()); } public TypeConverter GetConverter() { return TypeDescriptor.GetConverter(GetType()); } public EventDescriptor GetDefaultEvent() { return TypeDescriptor.GetDefaultEvent(GetType()); } public PropertyDescriptor GetDefaultProperty() { return TypeDescriptor.GetDefaultProperty(GetType()); } public object GetEditor(Type editorBaseType) { return TypeDescriptor.GetEditor(GetType(), editorBaseType); } public EventDescriptorCollection GetEvents() { return TypeDescriptor.GetEvents(GetType()); } public EventDescriptorCollection GetEvents(Attribute[] attributes) { return TypeDescriptor.GetEvents(GetType(), attributes); } public PropertyDescriptorCollection GetProperties() { return DynamicProperties_; } public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { var Props = DynamicProperties_.OfType(); var Filtered = Props.Where(x => x.Attributes.Contains(attributes)).ToArray(); return new PropertyDescriptorCollection(Filtered); } public object GetPropertyOwner(PropertyDescriptor pd) { return this; } public void SetDynamicValue(string Name, T Value) { Name = Name.Replace('-', '_'); DynamicPropertyDescriptor Descriptor = (DynamicPropertyDescriptor)DynamicProperties_.Find(Name, false); Descriptor.SetValue(this, Value); } public T GetDynamicValue(string Name) { Name = Name.Replace('-', '_'); DynamicPropertyDescriptor Descriptor = (DynamicPropertyDescriptor)DynamicProperties_.Find(Name, false); return (T)Descriptor.GetValue(this); } protected void AddDynamicProperty(string Name, Attribute[] Attributes) { Name = Name.Replace('-', '_'); // If we have a parent, find the corresponding PropertyDescriptor with the same // name from the parent. DynamicPropertyDescriptor ParentDescriptor = null; if (Parent_ != null) ParentDescriptor = (DynamicPropertyDescriptor)Parent_.GetProperties().Find(Name, false); DynamicProperties_.Add(new DynamicPropertyDescriptor(Name, ParentDescriptor, Name, Attributes)); } } }