Properties Created at Run Time (PropertyGrid.SelectedObject)

Well, that’s hard.

Introduction . My idea is to attach to the QueryBuilder the class I wrote in the PropertyGrid. The QueryBuilder class now contains a couple of fields that are hard-coded, as in the example below. Thus, the user can specify which fields should be used in the query, how (sorted, grouped, etc.). After the user has set all the settings for these properties (by code or through the GUI PropertyGrid), QueryBuilder will be able to fulfill the query. Everything works great. Pseudocode:

class QueryBuilder { public QBField name {get; set;} public QBField prename {get; set;} public QBField zip {get; set;} // ... public void QueryBuilder() { name = new QBField(); prename = new QBField(); // ... } public getQuery() { // logic to build the query } } class QBField { public bool shown {get; set;} public bool sortby {get; set;} public bool groupby {get; set;} } 

Problem: Now, instead of hard-coded each field as public properties in the QueryBuilder class, I was wondering how I could use ie List<string> containing all my fields to "populate" my QueryBuilder inquisitor using these properties.

So this leads to three questions:

  • Could this be achieved by overriding GetProperties () of the QueryBuilder class, and if so, what is the best way to do this?

  • How can I then iterate over all of them during the execution of the generated QBField properties and eliminate them? Idea: PropertyDescriptors and Activators?

  • How can I iterate over all these properties to read the values ​​of each QBField object? The problem I ran into was that when reading QBField properties with reflection and trying to getValue (obj, null), of course, the first necessary parameter is an object that I don't know, since I have a lot of these QBField objects. Perhaps putting all my QBFields in a List<QBField> and iterating through it? Will this work in this example?

I was just a little lost, but I feel that I am very close to a solution. Therefore, any help or just direction signs in the right direction is most appreciated!

+3
source share
1 answer

PropertyGrid can influence through TypeConverter , ICustomTypeDescriptor and / or TypeDescriptionProvider . Of these, TypeConverter is the simplest, overriding GetProperties (and marking it as supported).

In any case, you will also need to write an implementation of PropertyDescriptor , which knows how to take the field and object, and get / set the value, i.e.

 public override void SetValue(object component, object value) { ((YourType)component)[fieldNameSetInConstructor] = value; } 

Here is a basic property package that expands everything as a string ; obviously, as you extend this (different types of properties, change notifications, etc.), it becomes more complex very quickly. Also note that this TypeConverter approach TypeConverter works for PropertyGrid ; for DataGridView etc. you will need ICustomTypeDescriptor or TypeDescriptionProvider . For collections you will need ITypedList . In addition, for specific scenarios, there are about 20 other interfaces around the edges. But you understand: p The main thing is that our PropertyDescriptor acts as a translation between your actual model (the dictionary in my case) and the model that you display on the TypeDescriptor (fake properties for each key).

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Forms; static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var bag = new BasicPropertyBag { Properties = { new MetaProp("Name", typeof(string)), new MetaProp("Description", typeof(string)), new MetaProp("DateOfBirth", typeof(DateTime) , new CategoryAttribute("Personal"), new DisplayNameAttribute("Date Of Birth")) } }; bag["Name"] = "foo"; bag["DateOfBirth"] = DateTime.Today; Application.Run(new Form { Controls = { new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = bag } } }); } } public class MetaProp { public MetaProp(string name, Type type, params Attribute[] attributes) { this.Name = name; this.Type = type; if (attributes != null) { Attributes = new Attribute[attributes.Length]; attributes.CopyTo(Attributes, 0); } } public string Name { get; private set; } public Type Type { get; private set; } public Attribute[] Attributes { get; private set; } } [TypeConverter(typeof(BasicPropertyBagConverter))] class BasicPropertyBag { private readonly List<MetaProp> properties = new List<MetaProp>(); public List<MetaProp> Properties { get { return properties; } } private readonly Dictionary<string, object> values = new Dictionary<string, object>(); public object this[string key] { get { object value; return values.TryGetValue(key, out value) ? value : null; } set { if (value == null) values.Remove(key); else values[key] = value; } } class BasicPropertyBagConverter : ExpandableObjectConverter { public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { PropertyDescriptor[] metaProps = (from prop in ((BasicPropertyBag)value).Properties select new PropertyBagDescriptor(prop.Name, prop.Type, prop.Attributes)).ToArray(); return new PropertyDescriptorCollection(metaProps); } } class PropertyBagDescriptor : PropertyDescriptor { private readonly Type type; public PropertyBagDescriptor(string name, Type type, Attribute[] attributes) : base(name, attributes) { this.type = type; } public override Type PropertyType { get { return type; } } public override object GetValue(object component) { return ((BasicPropertyBag)component)[Name]; } public override void SetValue(object component, object value) { ((BasicPropertyBag)component)[Name] = (string)value; } public override bool ShouldSerializeValue(object component) { return GetValue(component) != null; } public override bool CanResetValue(object component) { return true; } public override void ResetValue(object component) { SetValue(component, null); } public override bool IsReadOnly { get { return false; } } public override Type ComponentType { get { return typeof(BasicPropertyBag); } } } } 
+5
source

Source: https://habr.com/ru/post/1334168/


All Articles