Доступ к дополнительным контекстным данным в EditValue UITypeEditor - PullRequest
4 голосов
/ 29 марта 2010

Я настраиваю приложение WinForms. Это приложение имеет Form, который содержит PropertyGrid. Объекту присваивается свойство SelectedObject, поэтому в сетке свойств отображаются свойства объекта.

Тип назначенного объекта имеет свойство, которое содержит EditorAttribute, определяющее UITypeEditor.

Эта реализация UITypeEditor возвращает UITypeEditorEditStyle.Drop в переопределении метода GetEditStyle. Его метод EditValue отображает ListBox, из которого может быть назначено значение для свойства экземпляра.

Все хорошо, пока хорошо.

Теперь у меня есть дополнительное требование, которое требует изменения доступных элементов в списке в зависимости от другого состояния Form, в котором находится PropertyGrid. Я не могу понять, как передать эту контекстную информацию в метод EditValue.

Кажется, в параметре context ничего нет, даже если я пытаюсь привести его к более конкретным типам. Я также не могу понять, как добавить какой-либо другой Сервис для извлечения из provider.

Есть идеи?

Ответы [ 3 ]

4 голосов
/ 06 февраля 2013

Я был в подобной ситуации, я хотел внедрить объект в конструктор моего пользовательского UITypeEditor.

Я последовал за комментарием Николаса Кадилхака в Здесь , ДАЙ ЕГО ВСЕ КРЕДИТ. Он использует TypeDescriptionProvider.

Вот полный набор кода.

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

2 голосов
/ 29 марта 2010

Интересно, лучше ли то, что вы пытаетесь сделать, как TypeConverter через GetStandardValues? Но так или иначе, context.Instance и context.PropertyDescriptor кажутся заполненными в быстром тесте (для GetEditStyle и 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()
                }
            }
        });
    }
}

Или как преобразователь типа:

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()
                }
            }
        });
    }
}
1 голос
/ 16 октября 2012

В переопределенном методе EditValue context.Container предоставит объект, к которому относится редактор. Свойство context.Container.Components выведет список всех элементов управления, включая форму и все ее дочерние элементы.

...