.NET Forum / Windows Forms / Design Time / December 2007
InheritedPropertyDescriptor vs. ReflectedPropertyDescriptor
|
|
Thread rating:  |
Notre Poubelle - 01 Mar 2007 00:58 GMT 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] - 01 Mar 2007 09:57 GMT 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 - 01 Mar 2007 17:10 GMT 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 - 02 Mar 2007 00:59 GMT 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 - 02 Mar 2007 06:15 GMT 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 - 02 Mar 2007 17:28 GMT 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 - 02 Mar 2007 18:44 GMT Notre,
Warning: long reply coming... <g>
> 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.
> 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.
 Signature Sergey Mishkovskiy http://www.usysware.com/dpack/ - free VS add-ons http://www.usysware.com/blog/
Notre Poubelle - 03 Mar 2007 03:09 GMT 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] - 05 Mar 2007 11:58 GMT 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.
> 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 - 05 Mar 2007 18:08 GMT 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] - 08 Mar 2007 02:45 GMT 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 - 09 Mar 2007 22:03 GMT 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.
> 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.
> 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)?
> 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.)
> 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.
>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?
>, 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.
> 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] - 14 Mar 2007 08:56 GMT Hi Notre,
Sorry for my delayed reply. I continue consulting to the experts in our discussion group.
> 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.
> 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.
> 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.
> 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 - 22 Mar 2007 23:07 GMT 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:
>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] - 29 Mar 2007 04:53 GMT 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 - 29 Mar 2007 17:48 GMT 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] - 06 Apr 2007 13:48 GMT 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 - 06 Apr 2007 23:02 GMT 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 - 04 Jun 2007 14:26 GMT Linda Liu [MSFT] - 09 Mar 2007 11:29 GMT 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 - 09 Mar 2007 22:27 GMT Hi Linda,
I don't know if I agree with this comment:
> 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:
>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.propertydescripto r.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.
> 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 - 10 Dec 2007 18:52 GMT 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.
> Hi Linda, > [quoted text clipped - 46 lines] > Thanks, > Notre Sergey M - 01 Mar 2007 14:51 GMT 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.
 Signature Sergey Mishkovskiy http://www.usysware.com/dpack/ - free VS add-ons http://www.usysware.com/blog/
> Hello, > [quoted text clipped - 27 lines] > Thanks, > Notre Notre Poubelle - 01 Mar 2007 17:41 GMT 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 - 01 Mar 2007 18:01 GMT Notre,
> Unfortunately, when I pass in <object>.GetType() > as an argument rather than <object>, I get back a different set of [quoted text clipped - 7 lines] > 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.
 Signature Sergey Mishkovskiy http://www.usysware.com/dpack/ - free VS add-ons http://www.usysware.com/blog/
Notre Poubelle - 02 Mar 2007 00:50 GMT 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
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|