1

我正在尝试自定义一个属性,如果我单击省略号按钮 [...],将显示一个新的对话框表单。不幸的是,表格不会显示。您能否检查以下代码并告知我哪里出错了?

using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System;

namespace Test01
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }


        void MainFormLoad(object sender, EventArgs e)
        {
            Form form = new Form();

            propertyGrid1.SelectedObject = new MyType();

        }
    }

    class MyType
    {
        private string bar;

        [Editor(typeof(FooEditor), typeof(UITypeEditor))]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public string Bar
        {
            get { return bar; }
            set { bar = value; }
        }
    }

    [Editor(typeof(FooEditor), typeof(UITypeEditor))]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    class Foo
    {
        private string bar;
        public string Bar
        {
            get { return bar; }
            set { bar = value; }
        }
    }
    class FooEditor : UITypeEditor
    {
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
        public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
        {
            IWindowsFormsEditorService svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
            Foo foo = value as Foo;
            if (svc != null && foo != null)
            {
                using (FooForm form = new FooForm())
                {
                    form.Value = foo.Bar;
                    if (svc.ShowDialog(form) == DialogResult.OK)
                    {
                        foo.Bar = form.Value; // update object
                    }
                }
            }
            return value; // can also replace the wrapper object here
        }
    }
    class FooForm : Form
    {
        private TextBox textbox;
        private Button okButton;
        public FooForm() 
        {
            textbox = new TextBox();
            Controls.Add(textbox);
            okButton = new Button();
            okButton.Text = "OK";
            okButton.Dock = DockStyle.Bottom;
            okButton.DialogResult = DialogResult.OK;
            Controls.Add(okButton);
        }

        public string Value
        {
            get { return textbox.Text; }
            set { textbox.Text = value; }
        }
    }
}
4

1 回答 1

3

您的编辑器使用该Foo类型(如果value不是Foo,则不会显示对话框),但您创建 的实例MyType,它包含一个Bar类型的属性,string然后您的FooEditor.

要尝试您的代码如何工作,您应该将属性Bar从更改stringFoo

class MyType
{
    private Foo bar = new Foo();

    [Editor(typeof(FooEditor), typeof(UITypeEditor))]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public Foo Bar
    {
        get { return bar; }
        set { bar = value; }
    }
}

示例
让我们看两个示例。在第一个中,您编辑Attribute已应用 的属性(然后您的编辑器更改属性本身的值):

这是您将在 中编辑的类PropertyGrid,我删除了Foo该类,因为对于此示例无用:

class MyType
{
    private string bar;

    [Editor(typeof(MyStringEditor), typeof(UITypeEditor))]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public string Bar
    {
        get { return bar; }
        set { bar = value; }
    }
}

这是将编辑您的Bar属性的编辑器。实际上它适用于任何类型的属性string

class MyStringEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        var svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
        string text = value as string;
        if (svc != null && text != null)
        {
            using (FooForm form = new FooForm())
            {
                form.Value = text;
                if (svc.ShowDialog(form) == DialogResult.OK)
                {
                    return form.Value;
                }
            }
        }

        return value;
    }
}

现在再举一个例子,编辑器不会更改属性值本身,而是更改该属性的属性值(编辑器应用于MyType.Bar(类型的Foo)属性,但它会更改.ValueFoo

Bar让我们再次为您的属性引入一个复杂类型:

class Foo
{
    private string _value;
    private object _tag; // Unused in this example

    public string Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public object Tag
    {
        get { return _tag; }
        set { _value = _tag; }
    }
}

更改MyType类以发布我们编写的复杂类型的一个属性,注意EditorAttribute现在使用特定于该Foo类型的新编辑器:

class MyType
{
    private Foo bar = new Foo();

    [Editor(typeof(FooEditor), typeof(UITypeEditor))]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public Foo Bar
    {
        get { return bar; }
        set { bar = value; }
    }
}

最后我们为类型编写编辑器Foo。请注意,此编辑器只会更改 property 的值,不会触及Foo.Value暴露的其他属性:Foo

class FooEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        var svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
        Foo foo = value as Foo;
        if (svc != null && foo != null)
        {
            using (FooForm form = new FooForm())
            {
                form.Value = foo.Value;
                if (svc.ShowDialog(form) == DialogResult.OK)
                {
                    // Updates the value of the property Value
                    // of the property we're editing. 
                    foo.Value = form.Value;
                }
            }
        }

        // In this case we simply return the original property
        // value, the property itself hasn't been changed because
        // we updated the value of an inner property
        return value;
    }
}

最后注意事项:在我们有来自 的更新值的if块中,属性(应用编辑器的地方)不会改变,但我们将更新它包含的实例的属性。大致相当于写这样的东西:svc.ShowDialog()FormBarValueFoo

MyType myType = new MyType();
myType.Bar.Value = form.Value;

如果我们只是为属性返回一个新值(如前面的示例),则Tag属性的旧值将丢失,如下所示:

MyType myType = new MyType();
Foo foo = new Foo();
foo.Value = form.Value;
myType.Bar = foo;

你能看到差别吗?无论如何,这将是一个教程而不是答案......

请注意,示例未经测试,我只是在这里写的,我只是想公开这个概念,而不是提供一个可靠的示例。

参考

在这里您可以找到有用资源的简短列表:

  • 关于如何工作的综合示例UITypeEditor
  • 文档的主要来源PropertyDescriptor始终是 MSDN,但在这里您可以找到一个非常简短的示例。
  • 如果您只需要本地化属性名称,您可以在 SO 上查看此条目
于 2013-02-28T10:07:34.233 回答