xml save Texture2D
As some of you’ve might seen, I’ve been breaking my head over the following problem for the past few days:
How do I serialize the class like the following without creating a special ‘intermediate’ struct for each and ever classes
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | public class MyData { [ContentSerializer(SharedResource = true)] public Texture2D myTexture; public int myInt; public string[] myLines; public MyData() { } // for deserialization public MyData(int myInt, Texture2DProxy myTexture, string[] myLines) { this.myInt = myInt; this.myTexture = myTexture; this.myLines = myLines; } } |
Even though I’ve marked the Texture2D as a shared resource, I still can’t serialize it using the IntermediateSerializer because a Texture2D always has a reference to a GraphicsDevice object, and the IS can’t serialize that.
Fortunately some helpfull people in #XNA on Efnet (ecosky and flashed, that’s you guys!) told me about proxyclasses, first I was confused and thought they wanted me to write a proxy for every class in my project, but soon they helped me understand that I should write a proxy class for Texture2D. I just had to write a proxy class that can be serialized and that will store the path to texture, so that it can reload itself when deserialized.
I quickly came up with the following class, very simple but it will suffice for now:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class Texture2DProxy { public Texture2DProxy(string path) { LoadTexture(path); } public Texture2DProxy() { } private void LoadTexture(string path) { ContentManager content = GameServices.GetService<ContentManager>(); //My own class, see my code snippet, you can also reference a static CM here. texture = content.Load<Texture2D>(path); this.path = path; } [ContentSerializerIgnore()] //make this is not serialized private Texture2D texture; [ContentSerializerIgnore()] public Texture2D Texture { get { if (texture == null) { LoadTexture(path); } return texture; } } [ContentSerializer()] //make sure this is, even-though it's a private field. private string path; } |
Now we just need to replace Texture2D with Texture2DProxy everywhere, and update some code. In the end we can now serialize and deserialize the MyData class like this:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | public void DoSerialize(MyData myData) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; using (XmlWriter writer = XmlWriter.Create("example.xml", settings)) { IntermediateSerializer.Serialize(writer, myData, null); } } public MyData DoLoad() { MyData tmp; XmlReaderSettings settings = new XmlReaderSettings(); using(XmlReader reader = XmlReader.Create("example.xml", settings)) { tmp = IntermediateSerializer.Deserialize<MyData>(reader, null); } return tmp; } |
Btw, serializing like this will generate the following XML file:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="utf-8"?><XnaContent> <Asset Type="XNASerialization.MyData"> <myTexture>#Resource1</myTexture> <myInt>42</myInt> <myLines> <Item>Two households, both alike in dignity,</Item> <Item>In fair Verona, where we lay our scene,</Item> <Item>From ancient grudge break to new mutiny,</Item> <Item>Where civil blood makes civil hands unclean.</Item> </myLines> </Asset> <Resources> <Resource ID="#Resource1" Type="XNASerialization.Texture2DProxy"> <path>latern</path> </Resource> </Resources></XnaContent> |
With this problem out of the way, I can now finally start working on a way to save and restore levels in Hollandia. Oh btw, you can ofcourse do the same trick with SoundEffects and Models or anything else for that matter.

浙公网安备 33010602011771号