Tuesday, February 2, 2010

PropertyGrid Control and Complex Type Object

For one of my last projects I decided to use the PropertyGrid Control, I assume it would be nice to use it as an editor for my complex type object.

Cheerful as I was it turn to be not such an easy mission, apparently the PropertyGrid Control can handle privitive types, collections and enums, but when it comes to complex type objects it need to be told what will be the way to edit them.

Here is the PropertyGrid as it was displayed originaly:








As you can see, the complex type “Manager” is not editable !!!

In order to make it editable it needs to be define with Editor Attribute, as such:

[Editor(typeof(MyUITypeEditor),typeof(UITypeEditor))]

In order to use this custom UITypeEditor, we’ll need to create two thins:
1. MyUITypeEditor - Based on the UITypeEditor.
2. UIMyClassEditorForm – The form that will be displayed whenever we’ll click the complex type for editing.

I really wanted this to be generic as I could so my UIMyClassEditorForm contains a PropertyGrid Control for editing the object pass through.

So now, when clicking the Manager property we should be abe to edit it and the screen will look like this:


Here is the source code:

Person.cs
public class Person
{
public enum City
{
NewYork,
TelAviv,
Rome
}

public Person() { }
public Person(string firstName, string lastName,int age, City myCity)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
this.MyCity = myCity;
this.Manager = new Person();
}

List children = new List();
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public City MyCity { get; set; }
public List Children
{
get { return children; }
}

[Editor(typeof(MyUITypeEditor),typeof(UITypeEditor))]
public Person Manager{ get; set; }

public override string ToString()
{
return string.Format("{0},{1}", FirstName, LastName);
}

}
MyProperyGridSampleForm.cs
public partial class MyProperyGridSampleForm : Form
{


public MyProperyGridSampleForm()
{
InitializeComponent();
}

private void EditPersonButton_Click(object sender, EventArgs e)
{
Person myTestEntity = new Person();
myTestEntity.FirstName = "John";
myTestEntity.LastName = "Smith";
myTestEntity.Age = 29;
myTestEntity.MyCity = Person.City.NewYork;
myTestEntity.Manager = new Person("Liron", "Leybovich", 33, Person.City.TelAviv);

propertyGrid1.SelectedObject = myTestEntity;
}
}
UIMyClassEditorForm.cs
public partial class UIMyClassEditorForm : Form
{
public object MyClass;
public IWindowsFormsEditorService _wfes;


public UIMyClassEditorForm()
{
InitializeComponent();
TopLevel = false;
}

private void UIMyClassEditorForm_Load(object sender, EventArgs e)
{
this.propertyGrid1.SelectedObject = MyClass;
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_wfes.CloseDropDown();
}

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


#region Edit Value
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider,
object value)
{
IWindowsFormsEditorService wfes = provider.GetService(
typeof(IWindowsFormsEditorService)) as
IWindowsFormsEditorService;

if (wfes == null) { return value; }

UIMyClassEditorForm form = new UIMyClassEditorForm();

if (value != null)
{
form.MyClass = value;
}
else
{
form.MyClass = new object();
}

form._wfes = wfes;

wfes.DropDownControl(form);

return value;
}
#endregion

}

All the best….
Liron