The title pretty much explains everything we will find in this article and solution to this question We will be using data from xml file to build our own data model and then finally displaying that to end user.



(Actual Question Image Link)


Basically this question answers three things as discussed below
1. Class Design to represent the actual data (as shown in image above)
2. Serialize/Deserialize the data from xml
3. Showing the deserialized data to end user



Step 1. To represent the data in data model we will just create following classes and the properties as shown below
(Hierarchy representing above model with dummy property Name as an example)

public class CommitteeDataModel
    {
        public CommitteeDataModel()
        {            
        }

        public static ObservableCollection<Committee> GetCommittees()
        {
            ObservableCollection<Committee> committee = new ObservableCollection<Committee>();
            committee.Add(new Committee() { Name = "Committee I" });
            committee.Add(new Committee() { Name = "Committee II" });
            committee.Add(new Committee() { Name = "Committee III" });
            return committee;
        }
    }

    public class Committee
    {
        public string Name { get; set; }
        public ObservableCollection<CommitteeAgenda> Agendas { get; set; }
        public Committee()
        {
            Agendas = new ObservableCollection<CommitteeAgenda>();
            Agendas.Add(new CommitteeAgenda() { Name = "CommitteeAgenda I" });
            Agendas.Add(new CommitteeAgenda() { Name = "CommitteeAgenda II" });
            Agendas.Add(new CommitteeAgenda() { Name = "CommitteeAgenda III" });
        }
    }

    public class CommitteeAgenda
    {
        public string Name { get; set; }
        public ObservableCollection<CommitteeAgendaItem> CommitteeAgendaItems { get; set; }
        public ObservableCollection<CommitteeAgendaDocument> CommitteeAgendaDocuments { get; set; }
        public CommitteeAgenda()
        {
            CommitteeAgendaItems = new ObservableCollection<CommitteeAgendaItem>();
            CommitteeAgendaItems.Add(new CommitteeAgendaItem() { Name = "CommitteeAgendaItem I" });
            CommitteeAgendaItems.Add(new CommitteeAgendaItem() { Name = "CommitteeAgendaItem II" });
            CommitteeAgendaItems.Add(new CommitteeAgendaItem() { Name = "CommitteeAgendaItem III" });

            CommitteeAgendaDocuments = new ObservableCollection<CommitteeAgendaDocument>();
            CommitteeAgendaDocuments.Add(new CommitteeAgendaDocument() { Name = "CommitteeAgendaDocument I" });
            CommitteeAgendaDocuments.Add(new CommitteeAgendaDocument() { Name = "CommitteeAgendaDocument II" });
            CommitteeAgendaDocuments.Add(new CommitteeAgendaDocument() { Name = "CommitteeAgendaDocument III" });
        }
    }

    public class CommitteeAgendaItem
    {
        public string Name { get; set; }

        public CommitteeAgendaItem()
        {

        }
    }

    public class CommitteeAgendaDocument
    {
        public string Name { get; set; }

        public CommitteeAgendaDocument()
        {

        }
    }



Step 2:  Serialize/Deserialize the data from xml
I ended up writing following functions to achieve this. Basically kind of boiler plate code which can be use to serialize any well formed class.

  • Write Committee class  object to xml.
 
 async Task writeXmlAsync()
        {
            IStorageFile xmlFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("Committees.xml", CreationCollisionOption.ReplaceExisting);

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(ObservableCollection<Committee>));
            MemoryStream memoryStream = new MemoryStream();
            ObservableCollection<Committee> committees = CommitteeDataModel.GetCommittees();
            xmlSerializer.Serialize(memoryStream, committees);
            memoryStream.Seek(0, SeekOrigin.Begin);
            string serialized = new StreamReader(memoryStream).ReadToEnd();
            memoryStream.Dispose();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(serialized);

            await xmlDoc.SaveToFileAsync(xmlFile);
        }


  • Read Committee class object from xml
async Task<ObservableCollection<Committee>> readXmlAsync()
        {
            ObservableCollection<Committee> committeesRead = null;
            IStorageFile xmlReadFile = await ApplicationData.Current.LocalFolder.GetFileAsync("Committees.xml");
            using (Stream stream = await xmlReadFile.OpenStreamForReadAsync())
            {
                XmlSerializer xmlReadSerializer = new XmlSerializer(typeof(ObservableCollection<Committee>));
                committeesRead = xmlReadSerializer.Deserialize(stream) as ObservableCollection<Committee>;
            }
            return committeesRead;
        }



Step 3: Showing the deserialized data in UI

Finally to show this data, I used the ListView to show this data as shown below (we are using Page derived from LayoutAwarePage)
Just Binding 

 <ListView ItemsSource="{Binding Committees}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <Grid Width="600" Height="30">
                                <TextBlock Text="{Binding Name}" Width="120" Height="30" />
                            </Grid>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

and inside LoadState I simply assign the collection of Committee like this. readXmlAsync function returns ObservableCollection<Committee>

protected override async void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            this.DefaultViewModel["Committees"] = await readXmlAsync();
        }


The data in inside Committee object like Agenda, Document, etc can be view in different UI Elements using Data Binding as shown above or simply can be fetched by traversing as shown in code below -
 
  ObservableCollection<Committee> lstCommittees = this.DefaultViewModel["Committees"] as ObservableCollection<Committee>;
            if (lstCommittees != null)
            {
                foreach (Committee committee in lstCommittees)
                {
                    string committeeName = committee.Name;
                    foreach (CommitteeAgenda committeeAgenda in committee.Agendas)
                    {
                        string committeeAgendaIdentifier = committeeAgenda.Name;
                    }
                }
            }

To follow exact question and answer trail follow here.