Pregunta

Estoy ajustando una aplicación WinForms. Esta aplicación tiene un Form que contiene un PropertyGrid. Se asigna un objeto al SelectedObject Propiedad para que la cuadrícula de propiedades muestre las propiedades para el objeto.

El tipo de objeto asignado tiene una propiedad que lleva un EditorAttribute especificando un UITypeEditor.

Esta implementación de UITypeEditor devoluciones UITypeEditorEditStyle.Drop en su anulación de GetEditStyle método. Su EditValue El método muestra un ListBox desde el cual se puede asignar un valor para la propiedad de instancia.

Todo bien hasta ahora.

Ahora tengo un requisito adicional que exige que los elementos disponibles en la lista se modifiquen en función de otro estado en poder del Form anfitrión del PropertyGrid. No puedo resolver cómo obtener esta información contextual al EditValue método.

No parece haber nada en el context Parámetro incluso si intento lanzarlo a tipos más específicos. Tampoco puedo averiguar cómo agregar algún otro servicio para recuperar del provider.

¿Algunas ideas?

¿Fue útil?

Solución

Me pregunto si lo que estás tratando de hacer sería mejor como un TypeConverter a través de GetStandardValues? Pero de cualquier manera, ambos context.Instance y context.PropertyDescriptor parecer ser poblado en una prueba rápida (para ambos GetEditStyle y 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()
                }
            }
        });
    }
}

O como un tipo de convertidor:

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()
                }
            }
        });
    }
}

Otros consejos

Estaba en una situación similar, quería inyectar un objeto en el constructor de mi UityPeeditor personalizado.

Seguí al comentario de Nicolas Cadilhac en Aquí, Dale todo el crédito. Utiliza typedescriptionProvider.

Aquí está el conjunto completo de código.

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();
    }
}

Miguel

En el método editValue anulado, context.Container Proporcionará el objeto al que pertenece el editor. los context.Container.Components La propiedad enumerará todos los controles que incluyen el formulario y todos sus hijos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top