Reputation: 13659
I'm trying to customize a property wherein if I click the elipses button [...] a new dialog form will be displayed. Unfortunately, the form won't show. Can you please check the below code and advise where did I go wrong?
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; }
}
}
}
Upvotes: 1
Views: 4368
Reputation: 67148
Your editor works with the Foo
type (if value
isn't Foo
then it won't show the dialog) but you create an instance of MyType
, it contains one property Bar
of type string
then it can't be edited by your FooEditor
.
To try how your code works you should change the property Bar
from string
to 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; }
}
}
EXAMPLES
Let's see two examples. In the first one you edit the property where the Attribute
has been applied (then your editor changes the value of the property itself):
This is the class you'll edit in the PropertyGrid
, I removed the Foo
class because useless for this example:
class MyType
{
private string bar;
[Editor(typeof(MyStringEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
public string Bar
{
get { return bar; }
set { bar = value; }
}
}
This is the editor that will edit your Bar
property. Actually it works with any property of type 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;
}
}
Now another example, the editor doesn't change the property value itself but the value of a property of that property (editor is applied to property MyType.Bar
(of type Foo
) but it changes the value of the property Value
of Foo
.
Let's introduce again a complex type for your Bar
property:
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; }
}
}
Change the MyType
class to publish one property of the complex type we wrote, note that the EditorAttribute
now uses a new editor specific for the Foo
type:
class MyType
{
private Foo bar = new Foo();
[Editor(typeof(FooEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
public Foo Bar
{
get { return bar; }
set { bar = value; }
}
}
Finally we write the editor for the Foo
type. Please note that this editor will change only the value of the property Foo.Value
, the other property exposed by Foo
won't be touched:
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;
}
}
Last notes: in the if
block of svc.ShowDialog()
we have the update value from the Form
, the property Bar
(where the editor is applied) won't be changed but we'll update the Value
property of the Foo
instance it contains. Roughly equivalent to write something like this:
MyType myType = new MyType();
myType.Bar.Value = form.Value;
If we just return a new value for the property (like in the previous example) the old value of Tag
property will be lost, something like this:
MyType myType = new MyType();
Foo foo = new Foo();
foo.Value = form.Value;
myType.Bar = foo;
Can you see the difference? Anyway it's going to be too more a tutorial than an answer...
Please note that examples are untested, I just wrote them here, I just would like to expose the concept more than to provide a surely working example.
REFERENCES
Here you can find a short list of useful resources:
UITypeEditor
worksPropertyDescriptor
documentation is always MSDN but here you can find a pretty short example.Upvotes: 3