views:

197

answers:

1

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?

+1  A: 

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()
                }
            }
        });
    }
}
Marc Gravell
Thanks Marc, perhaps my question needs tweaking, I need to access a value held by the _form_ that __isn't__ a value held by the object assigned to the `SelectedObject` property of the grid.
AnthonyWJones
@Anthony - Getting the form would be tricky - is there any way you could abstract it into the instance?
Marc Gravell
@Marc: I guess I could but I was hoping there was another way. I don't really want to pollute my data carrying objects to serve the application architecture's interests. It doesn't have to be the form itself just some other way to access additional data, thats really the role of the `IServiceProvider` but I can't find a way in this context to add my own service to be provided.
AnthonyWJones