自定义PropertyGrid控件

时间:2013-02-28 10:01:04

标签: c# .net winforms

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

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

1 个答案:

答案 0 :(得分:3)

您的编辑器使用Foo类型(如果value不是Foo,那么它不会显示对话框),但您创建了MyType的实例,它包含一个Bar类型的string属性,但您的FooEditor无法对其进行编辑。

要尝试代码的工作方式,您应该将属性Barstring更改为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; }
    }
}

<强>实施例
我们来看两个例子。在第一个编辑已应用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)但它会更改Value的属性Foo的值。

让我们再次为您的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类型的编辑器。请注意,此编辑器仅更改属性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的{​​{1}}区块中,我们拥有svc.ShowDialog()的更新值,属性Form(应用编辑器的位置)不会被更改但我们将更新它包含的Bar实例的Value属性。大致相当于写这样的东西:

Foo

如果我们只为属性返回一个新值(如上例所示),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; 如何运作的comprehensive example
  • UITypeEditor文档的主要来源始终是MSDN,here您可以找到一个非常简短的示例。
  • 如果您只需要本地化属性名称,可以查看this entry here on SO
相关问题