Working with XML Data Using LINQ, a TreeView, and a ListView :: Editing DataBy Miroslav Kadera
ASP.NET includes a variety of tools for displaying and editing XML documents. A previous article, Working with XML Data Using LINQ, a TreeView, and a ListView :: Displaying Data, showed how with a TreeView control, a ListView control, an XmlDataSource control, a LinqDataSource control, and about 50 lines of code we could create a web page that displayed the contents of a hierarchical XML file. Specifically, the page displayed the contents from a fictional employee phonebook, which allowed for an arbitrary number of employees nested within branches and departments. The TreeView and XmlDataSource controls displayed the various branches and departments, while the ListView and LinqDataSource controls displayed the employees belonging to the selected branch or department (or one of its subdepartments).
In addition to displaying data, the ListView and LinqDataSource controls can be augmented to edit, insert, and delete data. This article examines how to update the ListView and code to enable the visitor to add, edit, and delete employee phone records. By the conclusion of this article we will have constructed a web page that displays XML data and enables an end user to modify the data from a simple, easy-to-use web page interface. Read on to learn more!
|First Things First: Read the Displaying Data Article Before This One|
|This article builds upon the web page created in Working with XML Data Using LINQ, a TreeView, and a ListView :: Displaying Data. If you have not year read Working with XML Data Using LINQ, a TreeView, and a ListView :: Displaying Data, please do so before continuing with this article.|
Configuring the ListView to Support Editing
The ListView control, new to ASP.NET version 3.5, displays a series of records from a data source using templates. In addition to displaying data, the ListView control can be used to insert, edit, and delete data. Like the GridView control, the ListView control allows for in-line editing. That is, a user can select a particular record to edit from the list of displayed records, make her changes, and then update the data. The ListView also offers inserting functionality.
The principles of editing records in a ListView are very simple. We have to create a special template for the item being edited; this template,
is used to render the item being edited by the user. Additionally, we need to add a Button, LinkButton, or ImageButton control (usually in the
that has its
CommandName property set to "Edit". When this button is clicked, a postback occurs and the ListView is rebound to its data source
with this particular item rendered using its
ItemTemplate is straightforward enough: just add a LinkButton (or Button or ImageButton) with its
CommandName property set to "Edit":
Before we create the ListView's
EditItemTemplate, however, there is a complication in our specific situation that we need to first address.
Recall that the records displayed in the ListView may be located on different "levels" in our XML file (i.e. in various branches/departments). For example,
when select a particular branch or department from the TreeView on the left, the ListView displays not only the employees in that selected branch or department,
but all employees in descendent branches and departments as well. We need to be able to identify the correct branch or department an employee belongs to
when saving the edited values back to the XML file.
We can solve this problem by remembering the XPath address of the
Employee XML element when loading it in the ListView. To accomplish this we
need to add a property to our anonymous type returned by the LINQ query. The text in red shows the new anonymous type
We will later set this value as the
CommandArgument property of the "Update" LinkButton in the ListView's
As you can see from the LINQ query above, the
XPathAddress member assigned the value returned by the
getXPathAddress method, which
we need to create within the ASP.NET page's code-behind class. The method will iteratively traverse the passed-in
to the root element, building the
XPathAddress value as it walks up the tree:
Now that we know the XPath expression for each employee object, we can create the
EditItemTemplate. As you can see, the Update LinkButton's
CommandArgument property is assigned the
XPathAddress value returned by the LinqDataSource. We will need to use this value
in code to update the apporpriate employee record. Also note that instead of displaying the employee's name and phone number values in a Label, we use
TextBox Web controls instead.
You may be wondering why we used the
CommandName value of "XUpdate" instead of "Update". If we set the
CommandName to "Update",
the ListView will try to update the changes automatically by calling the data source control's
Update method. We have mapped the data
ourselves (in our
Selecting event handler), so our LinqDataSource can't serve as the updating source
in this case. We therefore have to write a method ourselves to save changes.
Saving the Editing Record Back to the XML File
We need to execute code when the "XUpdate" LinkButton has been clicked. The ListView's
ItemCommandevent is raised whenever a button with a
CommandNameproperty is clicked. Therefore, we need to create an event handler for this event. Keep in mind that this event handler will execute when any command button in the ListView is clicked; this includes the sorting and paging interface buttons. Consequently, it is imperative that we check the passed in
e.CommandNamevalue equals "XUpdate" before proceeding with our updating logic.
When the "XUpdate" button has been clicked, we need to save the changes and return the ListView to its pre-editing state. The following code illustrates
this functionality. Note that the data is saved by the
saveChanges method; we will create this method in a moment.
Our final task for editing records is to create the
saveChanges method, which saves the changes back to the XML file. As the above code
saveChanges method is passed two input parameters:
- The XPath address of the element being changed (recall that we assigned this
XPathAddressvalue to the Update button's
ListViewItembeing edited. Our method will search TextBoxes with new values in this
saveChangesmethod loads the
EmployeesXML element from the source file as an
XElementobject. The values of the
XElementobject are then modified to correspond with the user's entries. Finally, the updated
XElementobject is saved back to the XML file.
That's all there is to it! At this point a user can edit any existing employee phone record, changing their name, telephone number, or both.
Deleting Employee Phone Records
Deleting employee phone records works on a similar principle. We need to remember the
XPathAddressfor the employee and pass this to the event handler responsible for deleting the record. As with editing, we need to add a Delete LinkButton (or Button or ImageButton) to the ListView's
ItemTemplate. Set its
CommandNameproperty to "XDelete" and its
CommandArgumentproperty to the
XPathAddressvalue of the element to delete.
In the ListView's
ItemCommand event handler we need to handle the "XDelete" command. Like with the "XUpdate" command, we will call a
helper method (
deleteItem), passing it the XPath expression, and then return the ListView to its pre-editing state.
deleteItem method loads an
XElement object based on the supplied XPath expression, deletes it, and then saves the
contents of the XML file back to disk.
Adding New Employee Phone Records
Our final task is to enable the end user to add new employee phone records to the selected branch or department. Inserting an item from the ListView control is similar to editing an item in that both interfaces are defined through templates. To define the interface used for inserting, use the
InsertItemTemplate. This template can be shown as the first item in the ListView or as the last item.
InsertItemTemplate (shown below) looks similar to the EditItemTemplate in that it contains a TextBox Web control for the employee's name and
telephone number. Instead of an Update button, we have a Save button (whose
CommandName property is set to "XSave").
Like with the "XUpdate" and "XDelete" commands, we need to handle the "XSave" command in the ListView's
ItemCommand event handler. After
saving the item (via a call to
saveNewItem), we need to rebind the data to the ListView so that the just-added item appears in the list.
saveNewItem method is a bit more complicated than the
Part of the challenge stems from the fact that each element in the XML file has an
id attribute with a unique identifier for that
"level." So in adding a new element we need to choose an appropriate
saveNewItem method performs the following tasks:
- Load the root element (like in other methods)
- Get the
XPathAddressof the selected element in the TreeView and find the element in the XML file
- Get the maximum ID value from all elements in the parent element
- Create a new
- Add the new element to its parent and save the file
That's all, folks! With relatively small effort and a few lines of code we've created a fully-functional ASP.NET application for editing structured XML data. The main idea, on which the application is based, is the connection of TreeView and ListView, which enabled us to edit tabular data stored in more hierarchical XML structures. The bulk of the work is done for us by the TreeView, ListView, DataPager and LinqDataSource controls. All we had to do was write the code dealing with the location of record in various levels of the XML structure.