Working with XML Data Using LINQ, a TreeView, and a ListView :: Editing Data
By Miroslav Kadera
Introduction
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, EditItemTemplate,
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 ItemTemplate)
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 EditItemTemplate.
The ItemTemplate is straightforward enough: just add a LinkButton (or Button or ImageButton) with its CommandName property set to "Edit":
<ItemTemplate>
|
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
member, XPathAddress:
var query = from employeeElement in parentElement.Descendants("Employee")
|
We will later set this value as the CommandArgument property of the "Update" LinkButton in the ListView's EditItemTemplate.
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 employeeElement structure
to the root element, building the XPathAddress value as it walks up the tree:
private string getXPathAddress(XElement element)
|
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.
<EditItemTemplate>
|
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 LinqDataSource control's 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
ItemCommand event is raised whenever a button
with a CommandName property 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.CommandName value 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.
protected void lvwEmployees_ItemCommand(object sender, ListViewCommandEventArgs e)
|
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
shows, the 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'sCommandArgumentproperty) - The
ListViewItembeing edited. Our method will search TextBoxes with new values in thisListViewItem
saveChanges method loads the Employees XML element from the source file as an XElement object. The values
of the XElement object are then modified to correspond with the user's entries. Finally, the updated XElement object is
saved back to the XML file.
protected void saveChanges(string xPath, ListViewItem lvwItem)
|
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
XPathAddress for 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 CommandName property to "XDelete" and its CommandArgument property to the XPathAddress
value of the element to delete.
<asp:LinkButton ID="lnkDelete" runat="server"
|
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.
case "XDelete":
|
The 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.
protected void deleteItem(string xPath)
|
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.
The 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").
<InsertItemTemplate>
|
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.
case "XSave":
|
The saveNewItem method is a bit more complicated than the saveChanges or deleteItem methods.
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 id value.
The 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
XElementobject - Add the new element to its parent and save the file
protected void saveNewItem(ListViewItem lvwItem)
|
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.
Happy Programming!
Further Reading
Attachments




