.NET Forum / Windows Forms / Design Time / October 2006
IExtender Collection property Serialization problems
|
|
Thread rating:  |
Mick Doherty - 09 Oct 2006 12:45 GMT I have recently been playing with IExtenderProvider trying to implement a Collection Property and came upon this curious scenario:
If I set up a property to return a Componet Array the code is correctly serialized as follows: \\\ this.foo1.SetBar(this.button1, new FooBarExtension.FooBar[] { this.fooBar1}); ///
If, however, I change the return type to a Collection the property is incorrectly serialized like this: \\\ this.button1.BarCollection.AddRange(new FooBarExtension.FooBar[]{ this.fooBar2}); ///
Manually correcting it as follows has the desired effect: \\\ this.foo1.SetBarCollection(this.button1, new FooBarExtension.FooBarCollection(new FooBarExtension.FooBar[] {this.fooBar2})); /// ... but if I then change the items it is once again serialized incorrectly.
Can anyone offer an explanation of this as it has been driving me nuts?
The code used in this test follows: \\\ using System.Windows.Forms; using System.Globalization; using System.Reflection; using System.ComponentModel.Design.Serialization;
namespace FooBarExtension { [ProvideProperty("Bar",typeof(Control))] [ProvideProperty("BarCollection",typeof(Control))] public class Foo : System.ComponentModel.Component, IExtenderProvider { private System.ComponentModel.Container components = null; public Foo(System.ComponentModel.IContainer container) { container.Add(this); InitializeComponent(); } public Foo() { InitializeComponent(); } protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion bool IExtenderProvider.CanExtend(object extendee) { return extendee is Control; } private Hashtable bar = new Hashtable(); private Hashtable barCollection = new Hashtable(); public FooBar[] GetBar(object extendee) { if (bar.Contains(extendee)) return (FooBar[])bar[extendee]; return new FooBar[]{}; } public void SetBar(object extendee, FooBar[] value) { if (bar.Contains(extendee)) bar.Remove(extendee); bar.Add(extendee, value); } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public FooBarCollection GetBarCollection(object extendee) { if (barCollection.Contains(extendee)) return (FooBarCollection)barCollection[extendee]; FooBarCollection fbc = new FooBarCollection(); barCollection.Add(extendee, fbc); return fbc; } public void SetBarCollection(object extendee, FooBarCollection value) { if (barCollection.Contains(extendee)) barCollection.Remove(extendee); barCollection.Add(extendee, value); } }
[DesignTimeVisible(false)] public class FooBar : Component { public FooBar(){} public FooBar(string text) : this() { this.text=text; } private string text = ""; public string Text { get{return this.text;} set{this.text = value;} } public bool ShouldSerializeText() { return this.text != ""; } }
public class FooBarCollection : CollectionBase { public FooBarCollection() : base(){} public FooBarCollection(FooBar[] items) : this() { this.InnerList.AddRange(items); } public int Add(FooBar item) { return this.InnerList.Add(item); } public void AddRange(FooBar[] items) { this.InnerList.AddRange(items); } public void AddRange(FooBarCollection items) { this.InnerList.AddRange(items); } public void Remove(FooBar item) { this.InnerList.Remove(item); } public FooBar this[int index] { get{return this[index];} } } } ///
 Signature Mick Doherty http://dotnetrix.co.uk/nothing.html
Frank Hileman - 15 Oct 2006 18:58 GMT Hi Mick,
You should change DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
As long as it is set to Content, it will try to use Add or AddRange.
Regards, Frank Hileman
check out VG.net: http://www.vgdotnet.com Animated vector graphics system Integrated Visual Studio graphics editor
>I have recently been playing with IExtenderProvider trying to implement a >Collection Property and came upon this curious scenario: [quoted text clipped - 151 lines] > } > /// Mick Doherty - 17 Oct 2006 16:09 GMT Hi Frank,
I had thought about that and played with a custom serializer for the Collection class, but could not get a reference to the extender. I've not really worked with CodeDomSerializers and have found very little useful info on them.
I guess this is one of those things that's going to bug me for a while.
 Signature Mick Doherty http://dotnetrix.co.uk/nothing.html
> Hi Mick, > [quoted text clipped - 165 lines] >> } >> /// Frank Hileman - 18 Oct 2006 18:18 GMT Hi Mick,
I was referring to the attribute on GetBarCollection, which I thought was your code. That attribute is probably triggering the serialization behavior.
If you can avoid a custom serializer, I recommend that. Another thing to be aware of, perhaps this has been fixed, but in VS 2003 it would never serialize correctly a collection implementing AddRange(<array of your data type>), unless that collection was used for IComponent (sited) objects. Non-IComponent collections would serialize correctly just implementing Add(<your data type). This is unrelated to your other problem which I think is just the Content attribute setting.
- Frank
> Hi Frank, > [quoted text clipped - 174 lines] >>> } >>> /// Mick Doherty - 18 Oct 2006 19:52 GMT HI Frank,
Without the [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] attribute the collection does not serialize at all. I am aware of non IComponent based objects not serializing correctly and if you look closer, you'll see that I made the Collection Items class (FooBar) inherit from Component.
I did try not implementing the AddRange() method in the collection class, but this made no difference at all. The problem is not wholly in the method of serialization, but in the fact that the collection property of an IExtenderProvider is serialized as a property of the object which is being extended.
As far as I can tell, there is no way to fix my problem without writing a custom serializer for the collection class, but for the moment this has got the better of me.
I suppose the solution is just to use an Array instead of a Collection as this does serialize correctly, but then you lose all the benefits of the collection class.
I don't like to let these things get the better of me, and I shall fix it one day, but I'll put it aside for now and concentrate on other problems.
Thanks for trying to help.
 Signature Mick Doherty http://dotnetrix.co.uk/nothing.html
> Hi Mick, > [quoted text clipped - 191 lines] >>>> } >>>> /// Frank Hileman - 19 Oct 2006 00:50 GMT Hi Mick,
You can serialize non-IComponent classes in a collection, we do it with a few collections in VG.net. But I have never tried an IExtenderProvider provided collection, so probably you have hit some bugs specific to that. The AddRange error I mentioned was only ever manifested for non-IComponent types, and I think that is not related to your problem.
If you are serializing IComponent types, are they all sited correctly? Non-sited IComponent objects (with no designer) will not serialize correctly.
Frank
> HI Frank, > [quoted text clipped - 23 lines] > > Thanks for trying to help. Mick Doherty - 19 Oct 2006 14:59 GMT Hi Frank,
The Collection behaves exactly as expected if used as a property within a Control. Obviously the code example that I gave is not complete, but it should still work and for any class other than an IExtenderProvider, it does. The objects themselves are being correctly serialized. The Collection to which the objects belong is being serialized, but it is being serialized incorrectly. If I manually change the code to the correct CodeExpression, then the IDE will be happy, but if I change the collection at any time then the designers will rewrite the CodeExpression in an incorrect format.
This incorrect Serialization that I am seeing is very specific to IExtenderProviders.
I have no trouble getting non IComponent based classes to Serialize, I just add a TypeConvertor which returns an InstanceDescriptor and it generally serializes just fine. The real class that I was working with, does not implement IComponent. I reproduced a very basic example (I'm not really creating a FooBar Extender) and for simplicity made the class to be used as objects in the collection, Inherit from component. The result of this simple example is exactly the same as the much more complex example that I was working with.
 Signature Mick Doherty http://dotnetrix.co.uk/nothing.html
> Hi Mick, > [quoted text clipped - 37 lines] >> >> Thanks for trying to help.
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 ...
|
|
|