Julius Julius - 3 months ago 102
C# Question

C# XML Serialization in UWP

I am trying serialize more than one list to a unique xml file.
My project is a UWP, currrently it seems serialize my 3 list but the file is showed empty.
Previously a user help me with part of the code.
How I could correctly serialize it.


To execute my code only use: "project();"


All my code:

using Project.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using Windows.Storage;
using System.Threading.Tasks;

namespace Project
{
public class All_Classes
{
public class List1 : BindableBase
{
private int _Property1;
public int Property1
{
get { return _Property1; }
set { SetProperty(ref _Property1, value); }
}

private bool _Property2;
public bool Property2
{
get { return _Property2; }
set { SetProperty(ref _Property2, value); }
}

private bool _Property3;
public bool Property3
{
get { return _Property3; }
set { SetProperty(ref _Property3, value); }
}
}

public class List2 : BindableBase
{

private bool _Property1;
public bool Property1
{
get { return _Property1; }
set { SetProperty(ref _Property1, value); }
}

private bool _Property2;
public bool Property2
{
get { return _Property2; }
set { SetProperty(ref _Property2, value); }
}
}

public class List3 : BindableBase
{
private double _Property1;
public double Property1
{
get { return _Property1; }
set { SetProperty(ref _Property1, value); }
}

private double _Property2;
public double Property2
{
get { return _Property2; }
set { SetProperty(ref _Property2, value); }
}

private double _Property3;
public double Property3
{
get { return _Property3; }
set { SetProperty(ref _Property3, value); }
}

private double _Property4;
public double Property4
{
get { return _Property4; }
set { SetProperty(ref _Property4, value); }
}

}

public class Values_List1 : ObservableCollection<List1>
{
}
public class Values_List2 : ObservableCollection<List2>
{
}
public class Values_List3 : ObservableCollection<List3>
{
}

public static class ApplicationServices
{
public static Values_List1 List1 = new Values_List1();
public static Values_List2 List2 = new Values_List2();
public static Values_List3 List3 = new Values_List3();

static ApplicationServices()
{
}
}

public static void AddNewData()
{
ApplicationServices.List1.Add(new List1()
{
Property1 = 1,
Property2 = true,
Property3 = false,

});

ApplicationServices.List2.Add(new List2()
{
Property1 = false,
Property2 = true,
});

ApplicationServices.List3.Add(new List3()
{
Property1 = 3.564,
Property2 = 0.215,
Property3 = 0.7252,
Property4 = 23.463,
});
}

public static async void SaveObjectToXml<T>(T objectToSave)
{
//<-----------FilePicker------------------>
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("New File", new List<string>() { ".xml" });
savePicker.SuggestedFileName = "New File";
StorageFile newfile = await savePicker.PickSaveFileAsync();
//<-----------FilePicker------------------>
//<----------------Serializacion------------------>

var serializer = new XmlSerializer(typeof(T));

Stream stream = await newfile.OpenStreamForWriteAsync();


using (stream)
{
serializer.Serialize(stream, objectToSave);
}
//<----------------Serializacion------------------>

}

public class myCompoundClass
{
public List1 List1 { get; set; }
public List2 List2 { get; set; }
public List3 List3 { get; set; }
}

public static void project()
{
myCompoundClass new_instance = new myCompoundClass();
AddNewData();
SaveObjectToXml(new_instance);
}

}
}



I wanna get something similar to this:


<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<List1>
<Property1>1</Property1>
<Property2>true</Property2>
<Property3>false</Property3>
<ToAcero>0.1</ToAcero>
</List1>
<List2>
<Property1>true</Property1>
<Property2>true</Property2>
</List2>
<List3>
<Property1>3.564</Property1>
<Property2>0.215</Property2>
<Property3>0.7252</Property3>
<Property4>23.463</Property4>
</List3>
</Root>


Any help is appreciated.

dbc dbc
Answer

You never set any of the property values List1 or List2 or List3 inside your myCompoundClass:

        myCompoundClass new_instance = new myCompoundClass();
        AddNewData();
        // new_instance was not passed to AddNewData and so its properties have their default values of null.
        SaveObjectToXml(new_instance);

Thus all its properties will still be null. That's why your XML file is empty. You need to move your data from your static class ApplicationServices into the new_instance before serializing.

Update

You ask, how I can fill "new_instance" with ApplicationServices? Your problem is that you would like to serialize your ApplicationServices class but it is a static class and so cannot be serialized as-is. My suggestions would be:

  1. Rename your types. You have types such as List1 that are not lists. I'd suggest something like the following:

    public class Values1 : BindableBase // Formerly List1
    {
        // Contents unchanged
    }
    
    public class Values2 : BindableBase // Formerly List2
    {
        // Contents unchanged
    }
    
    public class Values3 : BindableBase // Formerly List3
    {
        // Contents unchanged
    }
    
    public class Values1List : ObservableCollection<Values1>
    {
    }
    public class Values2List : ObservableCollection<Values2>
    {
    }
    public class Values3List : ObservableCollection<Values3>
    {
    }
    

    Your existing naming conventions are misleading as to what is and is not a collection.

    Also, I suggest that you do not nest them inside the All_Classes class. Doing so adds complexity rather than clarity.

  2. Make the static value lists be read-only:

    public static class ApplicationServices
    {
        public static readonly Values1List List1 = new Values1List();
        public static readonly Values2List List2 = new Values2List();
        public static readonly Values3List List3 = new Values3List();
    
        static ApplicationServices()
        {
        }
    }
    
  3. Since you cannot serialize a static type, introduce the following data transfer object for serialization:

    [XmlRoot("Root")]
    public class ApplicationServicesDTO
    {
        [XmlElement]
        public Values1List List1 { get { return ApplicationServices.List1; } }
    
        [XmlElement]
        public Values2List List2 { get { return ApplicationServices.List2; } }
    
        [XmlElement]
        public Values3List List3 { get { return ApplicationServices.List3; } }
    }
    

    Some notes:

    • Note that the List properties are get-only. In general XmlSerializer will not serialize get-only properties, but it will serialize get-only collection properties when the collection is preallocated.

    • [XmlRoot("Root")] indicates that the type should be serialized with a root element named <Root>.

    • [XmlElement] applied to a collection property indicates that the collection should be serialized as a repeated sequence of elements without an outer container element.

Now you will be able to do:

var new_instance = new ApplicationServicesDTO();

And you static lists will get serialized with the XML format you want.

Note that if you later want to deserialize your XML, you may want to clear the pre-existing lists inside ApplicationServices first. For an explanation see XML Deserialization of collection property with code defaults.