Discussion:
InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor
(too old to reply)
Notre Poubelle
2007-03-01 00:58:00 UTC
Permalink
Hello,

I wonder if anyone can explain the difference between
InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor classes? I'm
writing my own designer based on the .NET design time framework. I've got a
custom design surface and am performing custom serialization with my own
designer loader.

Most everything works properly except in some cases where serialization is
concerned, some properties of controls do not get serialized. I call the
property descriptor's ShouldSerializeValue method to help decide whether a
control property should be serialized. In some cases, this method returns
True and in other cases False, when I would not expect it to return False.
I've read the description of PropertyDescriptor.ShouldSerializeValue and I
think I understand the rules that shoud be applied.

I get a list of properties by calling
TypeDescritpor.GetPRoperties(<object>,false). I've noticed in some cases my
properties are of type InheritedPropertyDescriptor while in other cases, they
are of type ReflectedPropertyDescriptor. It is when the properties are of
type InheritedPropertyDescriptor that the call to ShouldSerializeValue
returns False when I don't expect it to. Why do I sometimes get
InheritedPropertyDescriptor and other times get ReflectedPropertyDescriptor?
The rules seem to be different between the two classes...

Thanks,
Notre
Linda Liu [MSFT]
2007-03-01 09:57:20 UTC
Permalink
Hi Notre,

The ReflectPropertyDescriptor is an internal class, which we couldn't
access directly. We couldn't find any document about this class in MSDN. As
for the InheritedPropertyDescriptor you have mentioned, I couldn't find it
in MSDN or Reflector.

Have you implemented ICustomeTypeDescriptor on the control, or add a
CustomTypeDescriptionProvider to the control?

If possible, could you please send me a sample project that could just
reproduce the problem? To get my actual email address, remove 'online' from
my displayed email address.


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Notre Poubelle
2007-03-01 17:10:00 UTC
Permalink
Hi Linda,

Yes, I realize that ReflectPropertyDescriptor is an internal class that has
no MSDN documentation. Would you be able to speak with a developer on the
.NET framework team who may be able to clarify the differences between
ReflectPropertyDescriptor & InheritedPropertyDescriptor, when each gets
invoked by the framework, and differences in ShouldSerializeValue
implementations? (I imagine Brian Pepin or one of his colleagues may be able
to shed some more light).

I also discovered that the InheritedPropertyDescriptor class is not
documented in MSDN. It is available in the System.ComponentModel.Design
namespace in the System.Design assembly.

Yes, I have implemented ICustomTypeDescriptor on both the root designer
control (some of whose property descriptors use the
InheritedPropertyDescriptor class) & on most other controls (whose property
descriptors use the ReflectPropertyDescriptor class).

Unfortunately, I can't send you a sample project that demostrates the
problem as I'm not clear on where the problem (i.e. when some property
descriptors are using
the InheritedPropertyDescriptor class and others are using the
ReflectPropertyDescriptor class) is originating. The actually set of
controls, designers, and all the related pieces is quite big & integrated
with other parts of our system.

Thanks,
Notre
Notre Poubelle
2007-03-02 00:59:00 UTC
Permalink
Hi Linda,

In addition to my earlier comment (see above post), I did some more digging
on this. I'm still not clear on the intent of the
InheritedPropertyDescriptor class, but I now know when the property
descriptors get changed.

If I call TypeDescriptor.GetProperties(myObject, false), then some
properties come back as type InheritedPropertyDescriptor. Doing some further
digging, I find that GetProperties eventually calls
ITypeDescriptorFilterService.FilterProperties. This calls
IDesignerFilter.PostFilterProperties. This is implemented in
System.ComponentModel.Design.ComponentDesigner. The
InitialInheritedProperties method in this same class is the method that look
at all the properties and creates a set of InheritedPropertyDescriptor.

I'm still unclear of the why, and how to get my property to serialize...

Notre
Notre Poubelle
2007-03-02 06:15:04 UTC
Permalink
One more note -- I tried to use a DefaultValue attribute and then later a
ShouldSerialize<PropertyName> method, but neither helped in the case of the
properties that ended with an InheritedPropertyDescriptor.
Notre Poubelle
2007-03-02 17:28:18 UTC
Permalink
I have some more information. Some of my properties are of type
InheritedPropertyDescriptor (after the call to
TypeDescriptor.GetProperties(myObject, false)) and when I call
ShouldSerializeValue on some of these properties the value returned is True
(which is what I would expect). In the case of these properties, the
ShouldSerialize<PropertyName> method is called, unlike in the other
properties' cases, where ShouldSerializeValue always returns false.

Looking at implementation of
InheritedPropertyDescriptor.ShouldSerializeValue in Reflector, I found that
there is a test of see whether the property IsReadOnly. In both cases (when
ShouldSerializeValue works as expected and not), the IsReadOnly property
returns false.

The next test in InheritedPropertyDescriptor.ShouldSerializeValue is to
compare a private 'defaultValue' field against the static
InheritedPropertyDescriptor.noDefault field. Looking in the VS debugger, I
find something interesting. In both cases,
InheritedPropertyDescriptor.noDefault evaluates to {Object}. In the case
where things serialize as I expect (i.e. ShouldSerializeValue returns true),
then the 'defaultValue' field matches the
InheritedPropertyDescriptor.noDefault. In the case where it does not work as
expected, the 'defaultValue' field is different. The third test in
InheritedPropertyDescriptor.ShouldSerialize is then invoked, which compares
the value of the property vs. the 'defaultValue' field's value. If these two
don't match, then true is returned; otherwise
InheritedPropertyDescriptor.ShouldSerialize returns false.

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! This is why the method returns false. Using Reflector
again, I find that the 'defaultValue' field appears to be set in
InheritedPropertyDescriptor.InitInheritedDefaultValue, which is called from
the InheritedPropertyDescriptor constructor. By trial and error, and
examining the InitInheritedDefaultValue implementation in reflector, I
believe that the code is going into the branch that does this:

if (!this.propertyDescriptor.ShouldSerializeValue(component))
{
//Do stuff here - content removed by me for clarity
}
else
{
this.defaultValue =
this.propertyDescriptor.GetValue(component);
obj1 = this.defaultValue;
this.defaultValue =
this.ClonedDefaultValue(this.defaultValue);
}
That is, code execution goes into the else part of the if/else test and it
assigns the current value of the property to the defaultValue!

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...

Notre
Sergey M
2007-03-02 18:44:33 UTC
Permalink
Notre,

Warning: long reply coming... <g>
Post by Notre Poubelle
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.
Post by Notre Poubelle
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/
Notre Poubelle
2007-03-03 03:09:57 UTC
Permalink
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
Linda Liu [MSFT]
2007-03-05 11:58:36 UTC
Permalink
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.
Post by Notre Poubelle
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
Notre Poubelle
2007-03-05 18:08:05 UTC
Permalink
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.Initialize(). 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
Linda Liu [MSFT]
2007-03-08 02:45:53 UTC
Permalink
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
Notre Poubelle
2007-03-09 22:03:35 UTC
Permalink
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.
Post by Linda Liu [MSFT]
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.
Post by Linda Liu [MSFT]
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)?
Post by Linda Liu [MSFT]
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.)
Post by Linda Liu [MSFT]
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.
Post by Linda Liu [MSFT]
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?
Post by Linda Liu [MSFT]
, 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.
Post by Linda Liu [MSFT]
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
Linda Liu [MSFT]
2007-03-14 07:56:51 UTC
Permalink
Hi Notre,

Sorry for my delayed reply. I continue consulting to the experts in our
discussion group.
Post by Notre Poubelle
When you say root object here, are you referring to the designer host's
root object?

Yes, when I say the root object, I refer to the object returned from
IDesignerHost.RootComponent.
Post by Notre Poubelle
I'm also not clear on the other half of the statement 'since you are
inheriting from its base class'.

For the second half of the statement, let me try to elaborate. The
designer designs a class, say Class1. Class1 derives from some base class.
Class1.cs, which is the file you double click on to open the designer,
looks something like this:

public class Class1 : SomeBaseClass {}

The base class I'm referring to is "SomeBaseClass" above. The key
distinction is the designer does not create an instance of Class1 - it
can't, because that class isn't compiled - and instead it creates an
instance of SomeBaseClass. This instance is returned from
IDesignerHost.RootComponent.
Post by Notre Poubelle
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.

I think providing a sample demo of how this works for the Windows Forms
designer can be enlightening.

" Create a windows forms project, and add a button to the form. Mark the
control's member so it is "public" or "protected".
" Set the form's Title property to be "Form1".
" Now build the project, and add a new "Inherited Form". Choose Form1 as
the base class.
" You should now have a Form2 whose title says "Form1" and contains a
button.

Now let's manipulate form2:

" Change Form2's Title property to "Form2". The title on the form's title
bar should change.
" Right click on the Title property in the property grid and choose
"Reset". You should see the title get reset back to "Form1".

What's going on? The true default value for the Title property is an empty
string, but Reset changed it to Form1. The Title property of Form1 is
being provided by an InheritedPropertyDescriptor (IPD). The IPD saw that
the initialized value of the property was "Form1" and installed its own
DefaultValueAttribute with that value. When the property is reset, this
default value is applied to the property value. If we didn't do this,
resetting the property would change the title to an empty string, but that
isn't the behavior the user would see at runtime (at runtime the value
would be "Form1". Default values are never written to code, so the empty
string we reset the property to is lost).

Now:

" Click on the button and change its Text property
" Open the form2.designer.cs file and look at the generated code. There
should be a line that says "button1.Text = ¡­".

What's going on? Button1 was emitted into Form1 as a field. In order for
the field to be seen in the designer it must be added to the designer host
as a component. To do this, the inheritance code looks for fields in the
base class (Form1). These are actual fields (not properties) because that
is what the form designer emits when it declares a member for a control or
other component.
Post by Notre Poubelle
I have tried to use a DefaultValue attribute, but it doesn't help in the
case of the properties that ended with an InheritedPropertyDescriptor. 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.

If their properties are defined correctly and use either correct
DefaultValueAttributes or have a correct set of ShouldSerialize and Reset
methods, the inheritance logic should be invisible. You may have
properties set in MyRootComponent that cause the inherited property
descriptors to adopt different default values from what they expect.

Hope this helps.


Sincerely,
Linda Liu
Microsoft Online Community Support
Notre Poubelle
2007-03-22 22:07:12 UTC
Permalink
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
Post by Linda Liu [MSFT]
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
Linda Liu [MSFT]
2007-03-29 03:53:13 UTC
Permalink
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
Notre Poubelle
2007-03-29 16:48:00 UTC
Permalink
Hi Linda,

I think we're taking little steps closer to resolving this very long
discussion. Thanks for your continued involvement!

I think what we're starting to agree is that the DefaultValueAttribute does
not work for InheritedPropertyDescirptors. We also agree that the
ShouldSerialize method does work, but that it requires the return value to be
False at object construction time.

We also seem to agree that ReflectedPropertyDescriptor does not behave the
same as InheritedPropertyDescriptor. It has been my experience that a
ReflectedPropertyDescriptor will allow
PropertyDescriptor.ShouldSerializeValue to return True if either the
DefaultValueAttribute is used appropriately, the ShouldSerialize/Reset
methods are present (instead of the DefaultValueAttribute), or neither of
these two sets (DefaultValueAttribute or ShouldSerialize/Reset methods) are
present for the property. Based on my experience, and the latest comments in
your last post, InheritedPropertyDescriptor requires that a ShouldSerialize
method is present, and that this method must return false at construction
time.

Because these two classes behave differently, the developer needs to be
aware of the differences in these two internal classes so that he can
properly write his code such that his properties are serialized.

Thanks,
Notre
Linda Liu [MSFT]
2007-04-06 12:48:50 UTC
Permalink
Hi Notre,

Thank you for your persistence on this issue.

After discussion, Microsoft is considering on modifying the MSDN
documentation to remark how the InheritedPropertyDescriptor behaves
different from ReflectPropertyDescriptor.

You have helped us make progress and it's our honour to have a customer
like you : )

Have a nice weekend!

Cheers,

Linda Liu
Microsoft Online Community Support
Notre Poubelle
2007-04-06 22:02:02 UTC
Permalink
Thank you, your expert consult, and Sergey for all of your help in this
issue. It really took everyone to get it resolved.

Sincerely,
Notre
3***@h,d
2007-06-04 13:26:27 UTC
Permalink
just simple test
Linda Liu [MSFT]
2007-03-09 11:29:41 UTC
Permalink
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
Notre Poubelle
2007-03-09 22:27:05 UTC
Permalink
Hi Linda,
Post by Linda Liu [MSFT]
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.
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/library/system.componentmodel.propertydescriptor.shouldserializevalue.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.
Post by Linda Liu [MSFT]
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
donetcoder
2007-12-10 18:52:04 UTC
Permalink
I'm not sure I understand the work around or solution for this issue. I have
run into the same thing and this is the only info out there on this subject.
ShouldSerializeValue comes back false no matter what. I have tried the
ShouldSerializeMYMEMBERNAME but mine don't seem to be called.

Any help would be appreciated.
Post by Notre Poubelle
Hi Linda,
Post by Linda Liu [MSFT]
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.
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/library/system.componentmodel.propertydescriptor.shouldserializevalue.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.
Post by Linda Liu [MSFT]
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
Sergey M
2007-03-01 14:51:54 UTC
Permalink
Notre,

This is something we ran into just few short weeks ago while converting our
application to .NET 2.0. We also have a custom serializer, which recursively
serializes root design component with all of its sub-components. The
workaround was to check for root designer and process it slightly
differently. Here's a pseudo code snippet:

PropertyDescriptorCollection properties;
if (comp is <RootDesigner>)
// New for .NET 2.0 implementation
properties = TypeDescriptor.GetProperties(comp.GetType());
else
properties = TypeDescriptor.GetProperties(comp);
WriteProperties(properties, ...);

HTH.
--
Sergey Mishkovskiy
http://www.usysware.com/dpack/ - free VS add-ons
http://www.usysware.com/blog/
Post by Notre Poubelle
Hello,
I wonder if anyone can explain the difference between
InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor classes? I'm
writing my own designer based on the .NET design time framework. I've got a
custom design surface and am performing custom serialization with my own
designer loader.
Most everything works properly except in some cases where serialization is
concerned, some properties of controls do not get serialized. I call the
property descriptor's ShouldSerializeValue method to help decide whether a
control property should be serialized. In some cases, this method returns
True and in other cases False, when I would not expect it to return False.
I've read the description of PropertyDescriptor.ShouldSerializeValue and I
think I understand the rules that shoud be applied.
I get a list of properties by calling
TypeDescritpor.GetPRoperties(<object>,false). I've noticed in some cases my
properties are of type InheritedPropertyDescriptor while in other cases, they
are of type ReflectedPropertyDescriptor. It is when the properties are of
type InheritedPropertyDescriptor that the call to ShouldSerializeValue
returns False when I don't expect it to. Why do I sometimes get
InheritedPropertyDescriptor and other times get
ReflectedPropertyDescriptor?
The rules seem to be different between the two classes...
Thanks,
Notre
Notre Poubelle
2007-03-01 17:41:02 UTC
Permalink
Hi Sergey,

While I was attempting to research the InheritedPropertyDescriptor class on
the web, I found your earlier post on the subject ('Root designer and form
serialization problem'). Thanks for taking the time to respond to my post.

Thanks for the suggestion. I gave it a try and it's quite interesting. By
passing in <object>.GetType() rather than the <object> into
TypeDescriptor.GetProperties(), all the property descriptors that are
returned are of type InheritedPropertyDescriptor rather than
ReflectPropertyDescriptor. Unfortunately, when I pass in <object>.GetType()
as an argument rather than <object>, I get back a different set of proeprty
descriptors; I get a lot of extra ones that I don't need. The reason this
happens is because I'm implementing ICustomTypeDescriptor on my root control
(and most of my other controls) to filter the set of properties exposed. So,
using <object>.GetType() as the argument will not work for me; if I used it,
I would be serializing properties I don't want serialized. :(

Thanks,

Notre
Sergey M
2007-03-01 18:01:13 UTC
Permalink
Notre,
Post by Notre Poubelle
Unfortunately, when I pass in <object>.GetType()
as an argument rather than <object>, I get back a different set of proeprty
descriptors; I get a lot of extra ones that I don't need. The reason this
happens is because I'm implementing ICustomTypeDescriptor on my root control
(and most of my other controls) to filter the set of properties exposed.
So,
using <object>.GetType() as the argument will not work for me; if I used it,
I would be serializing properties I don't want serialized. :(
Yeah, I can see why that would be an issue for you. Take a look at
TypeDescriptor.GetProperties() overloads that take an array of Attribute as
a second parameter. I omitted that in my last reply but that's actually what
we use. Perhaps you could use that to filter out properties you don't want
to get serialized. It's been a while since I looked into that part of the
application, but if I recall it correctly, we use attributes filter to force
it to serialize extender properties. HTH.
--
Sergey Mishkovskiy
http://www.usysware.com/dpack/ - free VS add-ons
http://www.usysware.com/blog/
Notre Poubelle
2007-03-02 00:50:02 UTC
Permalink
Hi Sergey,

Thanks for your reply. I may go down this route, but I'd like to have a
better understanding of the InheritedPropertyDescriptor before I go down this
route, which might requiring changing some of my serialization design. I'm
going to wait a bit to see what Linda comes up with...

Thanks,
Notre
Loading...