expandableObjectConvertors TypeConverters

G

Guest

I have an object which I present to the user through a propertyGrid. With
many of the properties (many of which are objects themselves) I have
implemented my own TypeConverters; many of these inherit from the
ExpandableObjectConverter so that child properties are available to the user.

That all works swell.

Now I'm trying to create a print engine that will be able to print all
properties (Browsable). I thought this was going to be straightforward but I
have hit a snag....

I want to be able to go through the properties of my object and access the
all the child objects and their properties (essentially expanding them for my
print output)
Using the TypeDescriptor.GetProperties() I am able to get a collection of
all the 'first level Properties. I thought that getting at the Child object
properties would be as simple as using the TypeDescriptor.GetConverter()
method. This returns the TypeConvertor but I do not know how to determine if
it is of the expandable variety.

I tried looking at how the property grid accomplishes this but am having
difficulty. It looks like it uses the GetPropertiesSupported() Method on the
TypeDescriptor to determine if the object is expandable. I am trying this by
overriding the GetPropertiesSupported(ITypeDescriptorContext context) method.
However I don't really understand where I get the context from. I need an
example.

If anyone can help it would be appreciated.
 
M

Marc Gravell

Actually, TypeConverter.GetProperties is the exception for listing
properties; the "normal" approach is

TypeDescriptor.GetProperties(obj) or TypeDescriptor.GetProperties(obj,
attribs)

Note that neither requires a context - just a value - so you can
recurse i.e.

void ShowProps(object parentObj) {
foreach(PropertyDescriptor prop in
TypeDescriptor.GetProperties(obj)) {
object childObj = prop.GetValue(parentObj);
if(childObj != null) {
ShowProps(childObj);
}
// do something meaningful - i.e. WriteLine(prop.Name + "="
Convert.ToString(childObj));
}
}

Note, however, that for getting the string, the TypeConverter often
*is* the better approach (some conversions depend on the context); you
can write your own ITypeDescriptorContext class very easily (as
below), and use as:

Context ctx = new Context(parentObj, prop);

Make sense?

Marc

[ImmutableObject(true)]
public sealed class Context : ITypeDescriptorContext {
private readonly object component;
private readonly PropertyDescriptor property;
public Context(object component, PropertyDescriptor property)
{
this.component = component;
this.property = property;
}
IContainer ITypeDescriptorContext.Container {
get { return null; }
}

object ITypeDescriptorContext.Instance {
get { return component; }
}

void ITypeDescriptorContext.OnComponentChanged() {
}

bool ITypeDescriptorContext.OnComponentChanging() {
return true;
}

PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor {
get { return property; }
}

object IServiceProvider.GetService(Type serviceType) {
return null;
}
}
 
G

Guest

Thanks for the quick reply Marc,

Thanks for the info on the context. I thought that I had to get the context
from something existing... It didn't occur I just could create my own.

I definitely need access to the converter for this situation. However I
found that this method works...

I figured the 'appropriate' way to do this was to see if the TypeConverter
inherited the ExpandableObjectConvertor because the propertyGrid requires
this if the property can be expanded.

My problem was that the GetConverter Method returns a type of TypeConverter
by upcasting its converter. So if I tried
if (TypeDescriptor.GetConverter(property) is ExpandableObjectConverter){}
It would never return true.

So then I thought that the mechanism that the property grid used to may be
to call the GetPropertiesSupported() Method. (Presuambly an expandable
object would return true) (!!! I don't know if this is what happens by the
way, it would be super if MSDN described how this works somewhere but I
couldn't find anything). Thats when I was left in a quandry converning the
context argument.

I had a small but relevant breakthrough after I posted my original message.
I saw that, in the watch window, it knew about the converter that I had
decorated my object with. It turns out it is exposed as a property. So all
I had to do was..

foreach (PropertyDescriptor property in pdc)
{
if (property.Converter is ExpandableObjectConverter)
{
...
}

I am left wondering why does the GetConverter Method exist if they expose
the Converter as a property? Was the property exposed in a new version
leaving the method for legacy support?

Thaks again.

Greg






Marc Gravell said:
Actually, TypeConverter.GetProperties is the exception for listing
properties; the "normal" approach is

TypeDescriptor.GetProperties(obj) or TypeDescriptor.GetProperties(obj,
attribs)

Note that neither requires a context - just a value - so you can
recurse i.e.

void ShowProps(object parentObj) {
foreach(PropertyDescriptor prop in
TypeDescriptor.GetProperties(obj)) {
object childObj = prop.GetValue(parentObj);
if(childObj != null) {
ShowProps(childObj);
}
// do something meaningful - i.e. WriteLine(prop.Name + "="
Convert.ToString(childObj));
}
}

Note, however, that for getting the string, the TypeConverter often
*is* the better approach (some conversions depend on the context); you
can write your own ITypeDescriptorContext class very easily (as
below), and use as:

Context ctx = new Context(parentObj, prop);

Make sense?

Marc

[ImmutableObject(true)]
public sealed class Context : ITypeDescriptorContext {
private readonly object component;
private readonly PropertyDescriptor property;
public Context(object component, PropertyDescriptor property)
{
this.component = component;
this.property = property;
}
IContainer ITypeDescriptorContext.Container {
get { return null; }
}

object ITypeDescriptorContext.Instance {
get { return component; }
}

void ITypeDescriptorContext.OnComponentChanged() {
}

bool ITypeDescriptorContext.OnComponentChanging() {
return true;
}

PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor {
get { return property; }
}

object IServiceProvider.GetService(Type serviceType) {
return null;
}
}
I have an object which I present to the user through a propertyGrid. With
many of the properties (many of which are objects themselves) I have
implemented my own TypeConverters; many of these inherit from the
ExpandableObjectConverter so that child properties are available to the user.

That all works swell.

Now I'm trying to create a print engine that will be able to print all
properties (Browsable). I thought this was going to be straightforward but I
have hit a snag....

I want to be able to go through the properties of my object and access the
all the child objects and their properties (essentially expanding them for my
print output)
Using the TypeDescriptor.GetProperties() I am able to get a collection of
all the 'first level Properties. I thought that getting at the Child object
properties would be as simple as using the TypeDescriptor.GetConverter()
method. This returns the TypeConvertor but I do not know how to determine if
it is of the expandable variety.

I tried looking at how the property grid accomplishes this but am having
difficulty. It looks like it uses the GetPropertiesSupported() Method on the
TypeDescriptor to determine if the object is expandable. I am trying this by
overriding the GetPropertiesSupported(ITypeDescriptorContext context) method.
However I don't really understand where I get the context from. I need an
example.

If anyone can help it would be appreciated.
 
M

Marc Gravell

because the
propertyGrid requires this if the property can be expanded
I was under the impression that simply implementing
GetPropertiesSupported and GetProperties is sufficient. Unless I am
mistaken, ExpandableObjectConverter simply makes this easy (for simple
cases) by exposing the properties as per
TypeDescriptor.GetProperties - but I would *not* assume that only
ExpandableObjectConverter (and subtypes) can be expanded.
GetConverter Method returns a type of
TypeConverter by upcasting its converter.
Upcasting should be irrelevant; "is" should see through this... the
variable type and the object type are largely unrelated, unless the
variable type is sealed etc (and so the compiler knows it can't be
subclassed).
I tried
if (TypeDescriptor.GetConverter(property) is
ExpandableObjectConverter){}
You need "property.Converter"; the code you have posted asks for the
type-converter for the PropertyDescriptor class, which is not what you
want.
I am left wondering why does the GetConverter Method exist if they
expose the Converter as a property?
This is for getting the converter for a free-floating object, perhaps
a variable. This differs from the
converter-in-the-context-of-a-property, since the latter can override:
[TypeConverter(typeof(MyRandomConverter))]
public string SomeProp {...}
if (property.Converter is ExpandableObjectConverter)
I think you need to look at GetPropertiesSupported, not testing
against a type.
it would be super if MSDN described how this works somewhere
Well, they don't mention GetProperties() / GetPropertiesSupported(),
but:
http://msdn2.microsoft.com/en-us/library/ayybcxe5(VS.80).aspx
http://msdn2.microsoft.com/en-us/library/yy580hbd(VS.80).aspx
(both linked from
http://msdn2.microsoft.com/en-us/library/system.componentmodel.typeconverter(vs.80).aspx)

Marc
 

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