views:

336

answers:

3

I'm trying to serialize a class that derives from BindingList(Floor), where Floor is a simple class that only contains a property Floor.Height

Here's a simplified version of my class

[Serializable]
[XmlRoot(ElementName = "CustomBindingList")]
public class CustomBindingList:BindingList<Floor>
{
    [XmlAttribute("publicField")]
    public string publicField;
    private string privateField;

    [XmlAttribute("PublicProperty")]
    public string PublicProperty
    {
        get { return privateField; }
        set { privateField = value; }
    }
}

I'll serialize an instance of CustomBindingList using the following code.

XmlSerializer ser = new XmlSerializer(typeof(CustomBindingList));
StringWriter sw = new StringWriter();

CustomBindingList cLIst = new CustomBindingList();

Floor fl;

fl = new Floor();
fl.Height = 10;
cLIst.Add(fl);

fl = new Floor();
fl.Height = 10;    
cLIst.Add(fl);

fl = new Floor();
fl.Height = 10;
cLIst.Add(fl);

ser.Serialize(sw, cLIst);

string testString = sw.ToString();

Yet testString above ends getting set to the following XML:

<CustomBindingList xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"&gt;
    <Floor Height="10" />
    <Floor Height="10" />
    <Floor Height="10" />
</CustomBindingList>"

How do I get "publicField" or "publicProperty to serialize as well?

+1  A: 

This is known issue with XML serialization and inheriting from collections.

You can read more info on this here : http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/0d94c4f8-767a-4d0f-8c95-f4797cd0ab8e

You could try something like this :

[Serializable]
[XmlRoot]
public class CustomBindingList
{
    [XmlAttribute]
    public string publicField;
    private string privateField;

    [XmlAttribute]
    public string PublicProperty
    {
     get { return privateField; }
     set { privateField = value; }
    }

    [XmlElement]
    public BindingList<Floor> Floors = new BindingList<Floor>();
}

This means you can add floors by using Floors.Add and you will get the result you want, I hope, however, I didn't try it. Keep in mind that playing around with attributes is the key to XML serialization.

speps
A: 

XML serialization handles collections in a specific way, and never serializes the fields or properties of the collection, only the items.

You could either :

  • implement IXmlSerializable to generate and parse the XML yourself (but it's a lot of work)
  • wrap your BindingList in another class, in which you declare your custom fields (as suggested by speps)
Thomas Levesque
I ended up implementing IXMLSerializable. The problem with wrapping/encapsulating BindingList is that the point of using BindingList is it has events that allow it to be attach to GUI elements, like a DataGrid, very easy. So if I encapsulated the BindingList the resultant class wouldn't have any of those events.
Eric Anastas
You can always bind the DataGrid to the property that exposes the BindingList...
Thomas Levesque
+2  A: 

The short answer here is that .NET generally expects something to be a collection xor to have properties. This manifests in a couple of places:

  • xml serialization; properties of collections aren't serialized
  • data-binding; you can't data-bind to properties on collections, as it implicitly takes you to the first item instead

In the case of xml serialization, it makes sense if you consider that it might just be a SomeType[] at the client... where would the extra data go?

The common solution is to encapsulate a collection - i.e. rather than

public class MyType : List<MyItemType> // or BindingList<...>
{
    public string Name {get;set;}
}

public class MyType
{
    public string Name {get;set;}
    public List<MyItemType> Items {get;set;} // or BindingList<...>
}

Normally I wouldn't have a set on a collection property, but XmlSerializer demands it...

Marc Gravell