Access additional contextual data in EditValue UITypeEditor

I am setting up a WinForms application. This app has a Form that contains a PropertyGrid . The object is assigned to the SelectedObject property, so the property grid displays the properties of the object.

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

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

All is well good so far.

Now I have an additional requirement, which requires that the available items in the list be changed based on another state stored in the Form where the PropertyGrid located. I cannot figure out how to get this contextual information using the EditValue method.

There can be nothing in the context parameter, even if I try to apply it to more specific types. I also cannot decide how to add another service to retrieve from provider .

Any ideas?

+4
source share
3 answers

I wonder if what you are trying to do is better than TypeConverter via GetStandardValues ? But in any case, both context.Instance and context.PropertyDescriptor seem to be populated by a quick test (for 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() } } }); } } 
+2
source

I was in a similar situation, I wanted to inject an object into my own UITypeEditor constructor.

I followed Nicholas Cadillac's comment here , GIVE IT ALL CREDIT. It uses TypeDescriptionProvider.

Here is the complete set of code.

 class Foo { public Foo() { Bar = new Bar(); } public Bar Bar { get; set; } } class Bar { public string Value { get; set; } } class BarTypeDescriptionProvider : TypeDescriptionProvider { private TypeDescriptionProvider _baseProvider; string _extraParam; public BarTypeDescriptionProvider(Type t, string extraParam) { this._extraParam = extraParam; _baseProvider = TypeDescriptor.GetProvider(t); } public string ExtraParam { get { return _extraParam; } } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { return new BarTypeDescriptor(this, _baseProvider.GetTypeDescriptor(objectType, instance), objectType); } } class BarTypeDescriptor : CustomTypeDescriptor { private Type _objectType; private BarTypeDescriptionProvider _provider; public BarTypeDescriptor(BarTypeDescriptionProvider provider, ICustomTypeDescriptor descriptor, Type objectType): base(descriptor) { if (provider == null) throw new ArgumentNullException("provider"); if (descriptor == null) throw new ArgumentNullException("descriptor"); if (objectType == null) throw new ArgumentNullException("objectType"); _objectType = objectType; _provider = provider; } public override object GetEditor(Type editorBaseType) { return new BarEditor(_provider.ExtraParam); } } class BarEditor : UITypeEditor { private string _extraParam; public BarEditor(string x) : base() { _extraParam = x; } public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { MessageBox.Show(_extraParam); return base.EditValue(context, provider, value); } } public partial class Form1 : Form { public Form1() { InitializeComponent(); string extraParam = "Extra param from main form"; TypeDescriptor.AddProvider(new BarTypeDescriptionProvider(typeof(Bar), extraParam), typeof(Bar)); this.propertyGrid1.SelectedObject = new Foo(); } } 

Michael

+4
source

In an overridden method, EditValue context.Container will provide the object to which the editor belongs. The context.Container.Components property will display all controls that include the form and all its children.

+1
source

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


All Articles