XPathDocument, can you dig it? Yep, and you can edit it too.
Let's detail a problem set. You have a nice TreeView with a backing XML data store. Now, the user can update this data store using node changes, drag drops, or methods that create new nodes. Keeping up with the TreeView used to be a real pain in the neck, but the XPathDocument comes to the rescue. The code for each of these problems now becomes quite light. Let's check out some of the features.
We start by assuming that all tree nodes that we create on the Windows Forms side contain some information linking them back into the XML document. I do this by creating what I call the NavigatorTreeNode. This node basically props all of it's information based on the underlying XPathNavigator pointer. Now, I have no clue about the performance of creating hundreds of these little XPathNavigator objects, but I'm hoping they are lightweight. Here would be a sample tree node.
public class NavigatorTreeNode : TreeNode
{
private XPathNavigator navigator = null;
public XPathNavigator Navigator
{
get
{
return this.navigator;
}
set
{
this.navigator = value;
}
}
}
The first operation we'll define is an insert. Now that Whidbey has node-clicks you can store the currently clicked node whenever a context-menu is shown. With the current node, we have enough information to edit the underlying document and insert a new node. This can easily be done using:
XPathEditableNavigator editor = xPathDocument.CreateEditor();
editor.MoveTo(parentNode.Navigator); // Move to the current mark
editor = editor.AppendChild(“<Element />“);
editor.CreateAttribute(““, “NewAttribute“, ““, “Name of new Element“);
myNewNode.Navigator = editor.CreateNavigator();
The explanation for the above is to create a new editable navigator, move it to the point where we recorded reading our node, and finally begin to insert a new node and value representing our tree node that will be added to parent node. The next step is working with AfterLabelEdit so we can update our nodes whenever they change. AfterLabelEdit returns the node changed, and the label so not much work has to be done.
NavigatorTreeNode tn = e.Node as NavigatorTreeNode;
if (tn != null)
{
XPathEditableNavigator editor = xPathDocument.CreateEditor();
editor.MoveTo(tn.Navigator);
if (editor.MoveToAttribute("NewAttribute", ""))
{
editor.SetValue(e.Label);
}
}
Moving nodes around starts to get a bit more complicated, but not by much. You can use some overrides to make things really easy. Basically, you use the XPathNavigator of your node as a mark, then create an editor for the location you need the node inserted. Using these you can easily insert your old node path right into the new location, then delete you old node.
XPathEditableNavigator editor = xPathDocument.CreateEditor();
editor.MoveTo(insertBeforeMe.Navigator);
editor = editor.InsertBefore(nodeToMove);
XPathEditableNavigator deleteEditor = xPathDocument.CreateEditor();
editor.MoveTo(nodeToMove.Navigator);
editor.DeleteCurrent();
nodeToMove.Navigator = editor.CreateNavigator();
Think that covers a couple of options for sync'ing your tree nodes with your XPathDocument. I'm thinking there are probably some easier methods for doing a couple of these things. For instance, I'm surprised that I have to create an editor every time and move it to the navigator location. I could jus store editor's instead of navigators I guess, but I don't know about the overhead of using editor's in place of navigators everywhere. It's very odd that it takes two steps and I'd think XPathDocument should have some overrides that take XPathNavigator marks. That would cut out at least a single line of code.
Moving elements within the tree should be easier as well. A copy followed by a delete doesn't seem very cool and doesn't appear very transactional. I'm hoping they add the ability to move all elements from some XPathNavigator to somewhere else in the tree, immediately updating the XPathNavigator to the new location. That would take care of some of the work involved for sure.