Search code examples
c#winformspropertygriduitypeeditor

Accessing additional context data in EditValue of UITypeEditor


I'm tweaking a WinForms application. This application has a Form that contains a PropertyGrid. An object is assigned to the SelectedObject property so that the property grid displays the properties for the object.

The type of the object assigned has a property that carries an EditorAttribute specifying a UITypeEditor.

This implementation of UITypeEditor returns UITypeEditorEditStyle.Drop in its override of GetEditStyle method. Its EditValue method displays a ListBox from which a value for the instance property can be assigned.

All well an good so far.

Now I have an additional requirement which calls for the available items in the list to be modified based on other state held by the Form hosting the PropertyGrid. I can't work out how to get this contextual information to the EditValue method.

There doesn't seem to be anything on the context parameter even if I try casting it to more specific types. Neither can I work out how to add some other Service to retrieve from the provider.

Any ideas?


Solution

  • I wonder if what you are trying to do would would better as a TypeConverter via GetStandardValues? But either way, both context.Instance and context.PropertyDescriptor seem to be populated in a quick test (for both GetEditStyle and EditValue):

    using System;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.Windows.Forms;
    class MyData
    {
        [Editor(typeof(MyEditor), typeof(UITypeEditor))]
        public string Bar { get; set; }
    
        public string[] Options { get; set; }
    }
    class MyEditor : UITypeEditor
    {
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // break point here; inspect context
            return UITypeEditorEditStyle.DropDown;
        }
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // break point here; inspect context
            return base.EditValue(context, provider, value);
        }
    
    }
    class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new Form
            {
                Controls =
                {
                    new PropertyGrid {
                        Dock = DockStyle.Fill,
                        SelectedObject = new MyData()
                    }
                }
            });
        }
    }
    

    Or as a type-converter:

    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    class MyData
    {
        [TypeConverter(typeof(MyConverter))]
        public string Bar { get; set; }
    
        public string[] Options { get; set; }
    }
    class MyConverter : StringConverter
    {
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            MyData data = (MyData)context.Instance;
            if(data == null || data.Options == null) {
                return new StandardValuesCollection(new string[0]);
            }
            return new StandardValuesCollection(data.Options);
        }
    }
    class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new Form
            {
                Controls =
                {
                    new PropertyGrid {
                        Dock = DockStyle.Fill,
                        SelectedObject = new MyData()
                    }
                }
            });
        }
    }