HighTechTalks DotNet Forums  

InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor

Dotnet Framework (WinForms DesignTime) microsoft.public.dotnet.framework.windowsforms.designtime


Discuss InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor in the Dotnet Framework (WinForms DesignTime) forum.



Reply
 
Thread Tools Search this Thread Display Modes
  #11  
Old   
Sergey M
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-02-2007 , 01:44 PM






Notre,

Warning: long reply coming... <g>

Quote:
It turns out that in the case where things don't serialize as I expect,
the
'defaultValue' private field in InheritedPropertyDescriptor matches the
value
of the property!
Yeah, it's coming back to me now... Our .ShouldSerializeValue() calls were
failing after converting to .NET 2.0. Just as you are, I traced it down to
InheritedPropertyDescriptor. And inspecting it at run time I saw the same
thing, its default value was set to its current value, which
ShouldSerializeValue() happily treated as no serialization required
condition.

Quote:
I'm not 100% clear, but it looks like the InheritedPropertyDescriptor
object
is created each time TypeDescriptor.GetProperties(myObject, false) is
called,
so that the 'defaultValue' always matches the current property value;
therefore, ShouldSerializeValue always returns false...
I remember comparing FCL in 1.1 and 2.0 to see what's changed and do recall
finding a breaking change. BTW, it wasn't very helpful in the end anyways
cause I had to work around that somehow.

Anyways... Every designer's Initialize() is called eventually. The expected
pattern is to call base.Initialize(). Take a look at
ComponentDesigner.Initialize(). Notice that it calls
InitializeInheritedProperties() for the root component. This is where those
InheritedPropertyDescriptor are created for all inherited properties. The
difference between 1.1 and 2.0 implementations is that 2.0 adds
TypeDescriptor.Refresh(this.Component); at the end of
InitializeInheritedProperties(). That appears to cause those
InitializeInheritedProperties propagate to TypeDescriptor component cache.

I have a luxury of testing our serializer on 1.1 where everything works
fine. Calling TypeDescriptor.GetProperties(object) I don't see a single
instance of InheritedPropertyDescriptor returned. All I get there is, as
expected, bunch of ReflectedPropertyDescriptor. In 2.0 implementation,
TypeDescriptor.GetProperties(object) returns a mix of
InheritedPropertyDescriptor and ReflectedPropertyDescriptor properties.

Back to that TypeDescriptor.Refresh(this.Component); they've added. If you
recall, our work around was to call
TypeDescriptor.Refresh(RootComponent.GetType()), which confirms my findings.
Since they only refreshed component specific cache, we were still able to
use TypeDescriptor's component *type* cache, which wasn't "polluted" with
InheritedPropertyDescriptor instances.

I think it's either we're are missing something in our 2.0 designer stack
implementation, or it's a breaking 2.0 change. I'd be very surprised if this
issues will get any attention from Microsoft.
--
Sergey Mishkovskiy
http://www.usysware.com/dpack/ - free VS add-ons
http://www.usysware.com/blog/





Reply With Quote
  #12  
Old   
Notre Poubelle
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-02-2007 , 10:09 PM






Hi Sergey (and Linda),

Thanks for taking the time to write the long reply and reviewing your
solution to the problem. I realized today that I made a mistake in one of my
earlier posts: the DefaultValue attribute doesn't help me (as I earlier
posted) but the ShouldSerialize<PropertyName> appears to be a workaround.

Earlier, I thought that ShouldSerialize<PropertyName> was not being called
for some of the InheritedPropertyDescriptor objects. It turns out it is
called, at the point your described in your last post. I didn't have a
debugger attached nor a breakpoint set at this point in the component
initialization, so I didn't catch that it was actually being called.

Anyway once, I disovered it was called, the second problem was that my
ShouldSerialize<PropertyName> was always returning True. (My intent was just
for testing, to see if the ShouldSerialize<PropertyName> method would be
called). By always returning True, I was causing a problem for
InheritedPropertyDescriptor: the InitInheritedDefaultValue method (which is
called from InheritedPropertyDescriptor constructor) calls
ShouldSerializeValue on an internal property descriptor (the friendly
ReflectPropertyDescriptor) which calls my ShouldSerialize<PropertyName>. If
this call to ShouldSerializeValue returns true, then we get to the case where
the 'defaultValue' field is set to the current value of the property, and no
calls to InheritedPropertyDescriptor.ShouldSerializeValue bother to call my
ShouldSerialize<PropertyName> method anymore.

So, the solution again seems to be to implement
ShouldSerialize<PropertyName> and to make it such that it doesn't
unconditionally return True. I'm still doing some testing, but this looks
promising.

The outstanding questions I still have are:
1. An explanation for the difference between InheritedPropertyDescriptor and
ReflectPropertyDescriptor
2. Information on how often I need to write a ShouldSerialize<PropertyName>
method.
a. Do I need to do this for every single property I want to serialize?
(This is contrary to the PropertyDescriptor.ShouldSerializeValue
documentation).
b. Do I need to do it for every InheritedPropertyDescriptor?
c. How can I tell whether my property will end up being an
InheritedPropertyDescriptor as opposed to ReflectPropertyDescriptor, for
which this ShouldSerialize<PropertyName> is not neccessary?

Linda?

Thanks,
Notre

Reply With Quote
  #13  
Old   
Linda Liu [MSFT]
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-05-2007 , 06:58 AM



Hi Notre,

Thank you for your detailed explanation.

Sorry that I am still not very clear about your problem, even through I
understand it better than before.

Quote:
Most everything works properly except in some cases where serialization
is concerned, some properties of controls do not get serialized.

Could you tell me what the controls and what properites of the controls are
in the above sentence?

How the InheritedPropertyDescriptor is created, through the
ICustomTypeDescriptor.GetProperties method in your ICustomTypeDescriptor
implementation, or the PreFilterProperties method in your custom designer?
I never seen an InheritedPropertyDescriptor generated in my test. If
possible, could you please show me the relevant code of your
ICustomTypeDescriptor and the PreFilterProperties method in the custom
designer, if it exists?

Only after I get things clear, I could go on research on this issue and
give you possible assistance.
Thank you for your cooperation!

Sincerely,
Linda Liu
Microsoft Online Community Support



Reply With Quote
  #14  
Old   
Notre Poubelle
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-05-2007 , 01:08 PM



Hi Linda,

The control I noticed where some of its properties are not serializing
(before I introduced the ShouldSerialize<PropertyName> methods) is my 'root'
component. The class (let's call it MyFormWrapper) inherits from another
custom class (call it MyForm) which in turn derives from a UserControl.
MyFormWrapper adds some properties/events that are not present in MyForm and
hides some other properties that are available off the MyForm class.

The properties that are not serializing (without the help of the
ShouldSerialize<PropertyName> methods) are custom properties of custom types
(i.e. they are not in the .NET base class library). These properties are of
type 'A', 'B', or 'C', all of which inhert from a common custom class of type
'CustomBase' (which inherits from System.Object). (All these names are
fictional; giving the real names adds no value to the discussion). All of
the properties (of type 'A', 'B' and 'C') are attributed with the
BrowsableAttribute, with a value of False. (I did try changing the attribute
value to True but it made no difference to serialization).

I think the InheritedPropertyDescriptor objects are created, as Sergey says,
in System.ComponentModel.Design.ComponentDesigner.Ini tialize(). As Sergey
notes, it calls InitializeInheritedProperties() for the root component. When
my code later calls TypeDescriptor.GetPropeties(myFormWrapper, false), I get
back a set of InheritedPropertyDescriptor objects. My code does nothing
(that I know of) to suggest I want InheritedPropertyDescriptor objects vs.
ReflectPropertyDescriptor objects. The comment about PreFilterProperties
showing up some InheritedPropertyDescriptor objects is the first point in the
implementation of TypeDescriptor.GetPropeties where I notice some of the
property descriptors getting changed from ReflectPropertyDescriptor into
InheritedPropertyDescriptor.

I don't do anything in my custom type descriptor that I think should affect
what type of property descriptor is returned and I don't implement
PreFilterProperties (I'm talking about the behaviour of this method in the
BCL).

This is a complicated issue...! Hope this helps a bit.

Notre

Reply With Quote
  #15  
Old   
Linda Liu [MSFT]
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-07-2007 , 09:45 PM



Hi Notre,

I consulted this issue in our inner discussion group, and I got the
following reply.

InheritedPropertyDescriptor is used by the default ComponentDesigner to
stand in for properties that are inherited from a base class. There are
two cases where these property descriptors are added:

1. To the root object itself, since you are inheriting from its base class.
2. To fields found in the base class of the root object. Public and
protected fields from the base class are added to the designer so they can
be manipulated by the user.

InheritedPropertyDescriptor modifies the default value of properties so the
default value is the current value at object instantiation. As the
property was inherited from another instance, the designer must make it so
resetting the property value resets it to the value that was set by the
inherited class, which may differ from the default value stored in metadata.

Hope this helpful to you.


Sincerely,
Linda Liu
Microsoft Online Community Support


Reply With Quote
  #16  
Old   
Linda Liu [MSFT]
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-09-2007 , 06:29 AM



Hi Notre,

In addition, we should always write a ShouldSerialize<PropertyName> method
for each property we'd like to serialize. We should always use
TypeDescriptor.GetProperties(component) in our serializer and call the
ShouldSerializeValue method on each property to tell if it should be
serialized.

The fact that the component designer is substituting different property
descriptors should be invisible to you.

Hope this helps.

Sincerely,
Linda Liu
Microsoft Online Community Support


Reply With Quote
  #17  
Old   
Notre Poubelle
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-09-2007 , 05:03 PM



Hi Linda,

Thanks for consulting your inner discussion group. I'm not sure I
understand everything that you've said. I'll respond to some of your
statements inline.

Quote:
InheritedPropertyDescriptor is used by the default ComponentDesigner to
stand in for properties that are inherited from a base class.
This is what I'm seeing, in that the InheritedPropertyDescriptors are used
by the default ComponentDesigner. I'm not sure about the properties
inherited from a base class; see below for more questions on this.


Quote:
1. To the root object itself, since you are inheriting from its base class.
When you say root object here, are you referring to the designer host's root
object? That is, if I had function like this:

bool IsRootObject(IComponent)
{
IDesignerHost host = (IDesignerHost) GetService(typeof(DesignerHost));
if (component == host.RootComponent)
return true
return false;
}

then it could be used to determine whether a component is the deisgner's
root object? I'm asking to make sure we're using the same terminology.

I'm also not clear on the other half of the statement 'since you are
inheriting from its base class'. If my terminology matches yours for root
object, then my root object inherits once from a custom class first, and then
from a UserControl.
That is:
class MyRootComponent: MyBaseClass
{
}

class MyBaseClass: UserControl
{
}

Is it because the class of my root object inherits not directly from
System.Object or even UserControl but an intermediate class that I'm getting
InheritedPropertyDescriptors (or am I still not getting it)?

Quote:
2. To fields found in the base class of the root object. Public and
protected fields from the base class are added to the designer so they can
be manipulated by the user.

Ok, so this of course is dependent on my understanding of the earlier
statements, which may be wrong. Assuming my understanding of root object is
correct, then the properties which I'm seeing of type
InheritedPropertyDescriptor are not defined in either UserControl or
'MyBaseClass' but rather directly on the MyRootComponent class.

These properties (that are appearing as InheritedPropertyDescriptor) on
MyRootComponent do derive from a custom base class. I tried to explain this
in the previous post but may have been unclear; e.g.

MyTypeA Property1
{
get;
set;
}

MyTypeB Property2
{
get;
set;
}

where MyTypeA and MyTypeB are defined in terms of CommonBaseType, e.g.
class MyTypeA:CommonBaseType
{
}

class MyTypeB:CommonBaseType
{
}

This statement also talks about public and properted 'fields' from the base
type. Are we actually referring to field members of the class or properties
that wrap these fields?

Finally, "so they can be manipulated by the user". Are we talking about the
VS (or other designer hoster) end user here? Are we talking about
manipulating these propeties through a property grid? (I assume this is only
the case if we don't filter out properties via a custom type descriptor in a
derived type.)

Quote:
InheritedPropertyDescriptor modifies the default value of properties so the
default value is the current value at object instantiation.
Yes, this appears to be what is happening.

Quote:
As the
property was inherited from another instance
Are we again referring to a property (somewhere on the root or base class?)
being inherited from a derived class or the root object being derived from a
base class?

Quote:
, the designer must make it so
resetting the property value resets it to the value that was set by the
inherited class, which may differ from the default value stored in metadata.

The designer certainly does seem to set it to something different than what
is stored in the metadata, although I'm still confused as to why. Maybe some
clarifications to my comments above will enable me to understand.

Quote:
Hope this helpful to you.


Yes, it's a good step forward, although I don't understand everything yet.

Thanks for your persistence on this issue!

Notre


Reply With Quote
  #18  
Old   
Notre Poubelle
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-09-2007 , 05:27 PM



Hi Linda,

I don't know if I agree with this comment:

Quote:
In addition, we should always write a ShouldSerialize<PropertyName> method
for each property we'd like to serialize.
I'll explain why I'm not so sure in a moment. As for this comment:

Quote:
We should always use
TypeDescriptor.GetProperties(component) in our serializer and call the
ShouldSerializeValue method on each property to tell if it should be
serialized.

I completely agree with the above statement, and this is what I'm doing.
But this is where my concern with the previous statement (that we should
always write a ShouldSerialize<PropertyName> method for each property we wish
to serialize) comes in.

The documentation for PropertyDescriptor.ShouldSerializeValue
(http://msdn2.microsoft.com/en-us/lib...izevalue.aspx),
says that it first looks for a default value by looking for a
DefaultValueAttribute. If this is not found, then it looks for a
"ShouldSerializeMyProperty" method.

The documentation *does* say that you need to implement the
"ShouldSerializeMyProeprty" method, but I read this to mean that it not
actually required by the design pattern, but rather is a way of refining the
behaviour of PropertyDescriptor.ShouldSerializeValue beyond what is possible
with the DefaultValueAttribute.

I make this conclusion because of later statements in the documentation that
say: "If this method cannot find a DefaultValueAttribute or a
"ShouldSerializeMyProperty" method, it cannot create optimizations and it
returns true." This is NOT the case with the implementation of
InheritedPropertyDescriptor.ShouldSerializeValue; if I have not used a
DefaultValueAttribute (or even if do, it seems to make no difference) and if
do not include a "ShouldSerializeMyProperty", then
InheritedPropertyDescriptor.ShouldSerializeValue returns False rather than
True.

Quote:
The fact that the component designer is substituting different property
descriptors should be invisible to you.
I agree that this would be ideal, and it is what the documentation suggests
should be the case. However, my experience does not agree with this
statement, nor the documentation.

Thanks,
Notre


Reply With Quote
  #19  
Old   
Notre Poubelle
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-22-2007 , 06:07 PM



Hi Linda,

Sorry for my slow reply too! I was caught up in unrelated work until now.
I wanted to have time to digest your latest response before responding
further.

First, let me say that I did walk through the steps of the example you
provided and they did behave exactly as you suggested. The explanation does
help me to understand the general intent of the InheritedPropertyDescriptor
and why it exists. That was very helpful.

Clarification by what you meant by root object was also helpful in trying to
compare my code with your example and earlier explanations.

The fact that the designer is instantiating SomeBaseClass provides some
clarification as to why my properties are being changed into
InheritedPropertyDescriptor. What I'm not clear about is why not all of my
properties on the root object are of type InheritedPropertyDescriptor -- why
are some of the properties coming back as ReflectPropertyDescriptor?

One thing that may (?) make a difference is how these properties (at least
some of them) that turn into InheritedPropertyDescriptor are defined in my
case. This is the typical pattern:

private MyType _memberVariable;
[Browsable(false)]
public MyType MyProperty
{
get {
if (_memberVariable == null)
_memberVariable = new MyType();
//do other stuff
return _memberVariable;
}
set
{
_memberVariable = value;
}
}

In other words, these property are never "null", they always have a value
from the first time the property is accessed.

I have no doubt, based on my own experience that the ShouldSerialize method
helps in getting my properties serialized, even with
InheritedPropertyDescriptor. I don't think I need a Relect method, if my
property is never going to appear in the property grid -- does that sound
right to you?

Also, I'm still not getting anywhere with the DefaultValueAttribute. I
think your earlier explanation accurately captures what's happening:

Quote:
InheritedPropertyDescriptor modifies the default value of properties so the
default value is the current value at object instantiation. As the
property was inherited from another instance, the designer must make it so
resetting the property value resets it to the value that was set by the
inherited class, which may differ from the default value stored in metadata
My default value is never what I've statically defined using the
DefaultValueAttribute metadata. Instead, it is always the current value of
the property. So, if I use DefaultValueAttribute rather than the
ShouldSerialize (and maybe Reflect) method(s), then my properties that happen
to be of type InheritedPropertyDescriptor never get serialized.

Thanks,
Notre


Reply With Quote
  #20  
Old   
Linda Liu [MSFT]
 
Posts: n/a

Default Re: InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor - 03-28-2007 , 11:53 PM



Hi Notre,

The code that replaces properties with InheritedPropertyDescriptor is
selective and does not replace all properties. It does not replace:

1. Those properties that have a DesignOnly attribute set to true.
2. Those properties that are marked as
DesignerSerializationVisibility.Hidden and are not browsable to the user.

My understanding is that if the properties on the runtime class are defined
correctly the behavior should be correct.

From looking at InheritedPropertyDescriptor's code, it looks like if the
underlying property does not use DefaultValue attributes and instead uses
ShouldSerialize, the behavior to call ShouldSerialize and Reset methods
should be preserved provided that ShouldSerialize returned false at object
construction time.

Hope this helps.


Sincerely,
Linda Liu
Microsoft Online Community Support


Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.