Introduction
This article shows how the content of a WPF/MVVM TreeView can be saved and re-loaded with XML.
Background
A recent article [5] on Reading and Writing XML in C#/VB.Net discussed different options for using XML in .Net. This article builds on this base and gives a practical example with a demo application that is similar to the Solution Explorer Tool Window in Visual Studio.
Using the code
You should be able to just download the attached sample, open the project in VS 2017 Community, restore nuget packages, compile, and run (use the Forum below, if you have any questions).
The following screenshot shows the main window of the demo application:
You can use the context menu (see above) to arrange the items in the tree view. Use the Save button (see below) to save the content of the tree view.
The application shows a standard Save dialog that contains 2 file pattern options:
Choose the *.solsqlite option, if you prefer a binary relational data format as discussed in [4]. Choose the *.solxml option, if you want to save and load the contents of the tree view in good old plain XML.
Reloading data is implemented with the same workflow but using the Load button.
The sequence diagram below shows the workflow between the main objects participating in the interaction for saving the XML data:
The button click in MainWindow.xaml
invokes the bound ICommand SaveSolutionCommand
property in the AppViewModel
class, which in turn displays the standard file save dialog to let the user choose a file name, location, and the format.
The AppViewModel.Save_SolutionCommand_Async()
method then converts the viewmodel into a model as previously discussed for saving in the SQLite data format [4]:
The resulting tree model (shown above) is composed out of internal classes only. That is, everyone outside of the SolutionLibModels
library can only use the associated interfaces and the Factroy
class to interact with these data items.
The converted model is then handed over to the SolutionLibModels.Xml.Storage.WriteXmlToFile()
method that implements the actual serialization via DataContractSerializer
and IXmlSerializable
interface:
public static void WriteXmlToFile(string filename, ISolutionModel rootModel)
{
XmlWriter xmlWriter = null;
try
{
var fileStream = new FileStream(filename, FileMode.Create);
xmlWriter = XmlWriter.Create(fileStream, new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
CloseOutput = true
});
var dataContractSerializer = new DataContractSerializer(typeof(SolutionModel));
dataContractSerializer.WriteObject(xmlWriter, rootModel);
}
finally
{
if (xmlWriter != null)
xmlWriter.Close();
}
}
The WriteXmlToFile()
method is pretty much the same method that we have previously used to load and save XML [5] as shown in the DataContractSerializer_V1.zip sample. The above code in the Storage
class evaluates the ModelRoot
and sees the IXmlSerializable
interface. So, the DataContractSerializer
invoces the ModelRoot.WriteXml()
method and this invocations processes' all other ...WriteXml()
methods of all other tree view items, if they are processed as previously discussed [5].
The result of the invocation of all the IXmlSerializable
methods is hopefully an XML file that should be loadable upon a click on the Load button.
The processing for the loading of the XML Data is very similar - so I leave the explicit explanation out of here.
Conclusions
The above sample also shows an interesting reason for the seemingly additional (useless) burden of having to convert between viewmodel and models. We note that the attached implementation does not have a direct reference from the viewmodel to an XML serializer and/or SQLite storage solution. These references are only visible on the library that implements the model. We can. thus, claim that the model/viemodel conversion ensure a separation of concerns, which in turm will ensure a healthy and simplified development of this code.
Thats it. This is pretty much what I wanted to say about loading and saving WPF tree view content via XML. The sample presented in this article implements the lessons learned from [5], so you should at least read the section about the DataContractSerializer_V1.zip sample in order to understand how the IXmlSerializable
interface works here (if you got lost). Otherwise, you are always welcome to leave feedback and ask questions if you feel like something important is missing or plain wrong.
References