PropertyGrid and embedded structs... odd behaviour

G

Guest

Ok... I've just spend my entire friday to see how propertygrids and structs
are supposed to work. Whenever I create an instance of a class which has a
struct embedded, and I set the SelectedObject of my propertygrid to that
instance, I cannot seem to successfully change values of that embedded
struct, values are constantly reset. If I set the SelectedObject directly to
the struct instance, I CAN change the values. This is demonstrated in the
following code:

public partial class Form1 : Form
{
private PropertyGrid propertyGrid1;

[TypeConverter(typeof(ExpandableObjectConverter))]
public struct Foo
{
private float m_SomeValue;

public float SomeValue
{
get { return m_SomeValue; }
set { m_SomeValue = value; }
}
}

public class Bar
{
private Foo m_Foo = new Foo();

public Foo Foo
{
get { return m_Foo; }
set { m_Foo = value; }
}
}

private Bar m_Bar = new Bar();

public Form1()
{
InitializeComponent();

this.propertyGrid1.SelectedObject = m_Bar;
}

private void InitializeComponent()
{
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
this.SuspendLayout();
//
// propertyGrid1
//
this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid1.Location = new System.Drawing.Point( 0, 0 );
this.propertyGrid1.Name = "propertyGrid1";
this.propertyGrid1.Size = new System.Drawing.Size( 292, 266 );
this.propertyGrid1.TabIndex = 0;
//
// Form1
//
this.ClientSize = new System.Drawing.Size( 292, 266 );
this.Controls.Add( this.propertyGrid1 );
this.Name = "Form1";
this.ResumeLayout( false );

}
}

Ok, what's the magic here? And why do other valuetypes like the Rectangle
work correctly? IF I need to write my own typeconverter, what's the catch
exactly? I don't see anything spectaculair when I use reflector on the
RectangleConverter. Please help!

Regards,
Jelle
 
G

Guest

k, I've finally found the solution myself. I've seen more people struggling
with it, so here's the solution:

Embedded structures will not work just out of the box. This is of course
because value types are copied when they are retrieved by the propertygrid.
The propertygrid assumes that a reference type is used by default - the set
property is never called.
All of this changes when you provide your own TypeConverter and override the
CanCreateInstance and CreateInstance method. There is little documentation on
it, but if you use Reflector you can see how existing type converters handle
this. CreateInstance will naturally return a new object based on the
properties, and if CanCreateInstance returns true, the set method of your
property is called.

A good example to browse with Reflector is Rectangle for the 1.0 or 1.1
framework and Padding is a good example if you use the 2.0 framework.


Jelle van der Beek said:
Ok... I've just spend my entire friday to see how propertygrids and structs
are supposed to work. Whenever I create an instance of a class which has a
struct embedded, and I set the SelectedObject of my propertygrid to that
instance, I cannot seem to successfully change values of that embedded
struct, values are constantly reset. If I set the SelectedObject directly to
the struct instance, I CAN change the values. This is demonstrated in the
following code:

public partial class Form1 : Form
{
private PropertyGrid propertyGrid1;

[TypeConverter(typeof(ExpandableObjectConverter))]
public struct Foo
{
private float m_SomeValue;

public float SomeValue
{
get { return m_SomeValue; }
set { m_SomeValue = value; }
}
}

public class Bar
{
private Foo m_Foo = new Foo();

public Foo Foo
{
get { return m_Foo; }
set { m_Foo = value; }
}
}

private Bar m_Bar = new Bar();

public Form1()
{
InitializeComponent();

this.propertyGrid1.SelectedObject = m_Bar;
}

private void InitializeComponent()
{
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
this.SuspendLayout();
//
// propertyGrid1
//
this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid1.Location = new System.Drawing.Point( 0, 0 );
this.propertyGrid1.Name = "propertyGrid1";
this.propertyGrid1.Size = new System.Drawing.Size( 292, 266 );
this.propertyGrid1.TabIndex = 0;
//
// Form1
//
this.ClientSize = new System.Drawing.Size( 292, 266 );
this.Controls.Add( this.propertyGrid1 );
this.Name = "Form1";
this.ResumeLayout( false );

}
}

Ok, what's the magic here? And why do other valuetypes like the Rectangle
work correctly? IF I need to write my own typeconverter, what's the catch
exactly? I don't see anything spectaculair when I use reflector on the
RectangleConverter. Please help!

Regards,
Jelle
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top