WPF: XmlDataProvider Two-Way Data Binding - Enhanced
How to perform two-way data binding with the XmlDataProvider within the Windows Presentation Foundation including all CRUD operations.
Introduction
In my previous article, WPF: XmlDataProvider Two-Way Data Binding, I discussed how the XmlDataProvider
does not natively support two-way binding and provided a simple workaround to address the issue. The binding in the previous article only demonstrated read and update operations. In response to several reader comments inquiring about insert
and delete
operations, I have updated the demo code and provided this brief article.
Background
The application in my previous article was developed with Visual Studio 2008 and targeted the 3.5 version of the .NET framework. The downloadable project above for this article was upgraded to Visual Studio 2010.
Using the Code
You will notice from the screenshot below that I have added two new buttons to the form for the purpose of inserting and deleting records. Each button has a corresponding event handler to persist the changes to the source XML file.
We'll start with the New button and its event handler. The button simply removes the listbox
selection and clears the Team form to prepare for a new record.
private void NewTeamButton_Click(object sender, RoutedEventArgs e)
{
TeamsListBox.SelectedIndex = -1;
TeamIDTextBox.Text = String.Empty;
TeamNameTextBox.Text = String.Empty;
ConferenceTextBox.Text = String.Empty;
}
The event handler for the Save button has been enhanced to accommodate for new records. In the previous article, the Save button simply persisted the XmlDataProvider
's XmlDocument
to the underlying source XML file. That approach works well for update
operations as any changes to the UI are automatically synchronized in the XmlDataProvider
's XmlDocument
through its binding. The enhanced event handler will search the XmlDataProvider
's XmlDocument
, using XPath
, for the Team ID located in the TeamIDTextBox
. If the ID is not found, the code builds the necessary XML nodes to represent the new team and then adds it to the XmlDataProvider
's XmlDocument
. Lastly, the XmlDataProvider
's XmlDocument
is persisted to the source XML file.
private void SaveTeamsButton_Click(object sender, RoutedEventArgs e)
{
string source = TeamData.Source.LocalPath;
// Get a handle on the source data file.
XmlDocument doc = TeamData.Document;
// Get a handle on the root node.
XmlNode root = doc.SelectSingleNode("//Teams");
// Attempt to find the Id in the data file.
string xpath = "//Team[Id=" + TeamIDTextBox.Text + "]";
XmlNode currentNode = root.SelectSingleNode(xpath);
// If currentNode is null, then we add a new team with the data entered. If found,
// we simply call the save method to persist the updated data to the data file.
if (currentNode == null)
{
XmlNode newTeam = doc.CreateElement("Team");
XmlNode newTeamId = doc.CreateElement("Id");
XmlNode newTeamName = doc.CreateElement("Name");
XmlNode newTeamConference = doc.CreateElement("Conference");
newTeamId.InnerText = TeamIDTextBox.Text;
newTeamName.InnerText = TeamNameTextBox.Text;
newTeamConference.InnerText = ConferenceTextBox.Text;
newTeam.AppendChild(newTeamId);
newTeam.AppendChild(newTeamName);
newTeam.AppendChild(newTeamConference);
root.AppendChild(newTeam);
}
// Save the changes.
TeamData.Document.Save(source);
}
You will notice that the Delete button event handler looks familiar. It uses the same code as the Save button to find the currently selected record within the XmlDataProvider
's XmlDocument
. If found, the XmlNode
that represents the current record is removed from the XmlDocument
and the changes are persisted to the source XML file.
private void DeleteTeamsButton_Click(object sender, RoutedEventArgs e)
{
// Get the physical path for saving later.
string source = TeamData.Source.LocalPath;
// Get a handle on the source data file.
XmlDocument doc = TeamData.Document;
// Get a handle on the root node.
XmlNode root = doc.SelectSingleNode("//Teams");
// Get the currently selected node within the source data file.
string xpath = "//Team[Id=" + TeamIDTextBox.Text + "]";
XmlNode currentNode = root.SelectSingleNode(xpath);
if (currentNode != null)
{
// Delete the record.
root.RemoveChild(currentNode);
// Save the changes.
TeamData.Document.Save(source);
}
}
Conclusion
Even though the XmlDataProvider
has its limitations, they can easily be overcome with a small amount of code. I hope that this article has been informative.
History
- Version 1 - WPF: XmlDataProvider Two-Way Data Binding