Использование XML и LINQ в элементах управления TreeView и ListView - Редактирование информации

ОГЛАВЛЕНИЕ

Редактирование информации

ASP.NET включает в себя множество инструментов для отображения и редактирования XML-документов. Предыдущая статья по теме отображения информации демонстрировала способ создания веб-страницы, отображающей содержимое иерархического XML-файла при помощи элементов управления TreeView, ListView, XmlDataSource, LinqDataSource и примерно 50 строк кода. В частности, страница отображала содержимое фиктивной телефонной книжки с номерами сотрудников, которая позволяла хранить неопределенное число сотрудников,  вложенных в отделы и филиалы компании. Элементы управления TreeView и XmlDataSource отображали различные филиалы и отделы, в то время как ListView и LinqDataSource отображали сотрудников, принадлежащих к выбранному отделу или филиалу.

В дополнение к отображению информации ListView и LinqDataSource могут быть расширены таким образом, чтобы они поддерживали редактирование, вставку и удаление информации. Данная статья исследует способ обновления ListView и кода, тем самым позволяя посетителям добавлять, редактировать и удалять записи о телефонах сотрудников. Результатом данной статьи будет веб-страница, которая отображает XML-информацию и позволяет пользователю обновлять ее из простого, легкого в использовании, интерфейса веб-страницы. Читайте далее, чтобы узнать больше об этом!

Настройка ListView для поддержки редактирования

Элемент управления ListView, предоставленный в ASP.NET версии 3.5, отображает серию записей из источника данных при помощи шаблонов. В дополнение к выводу информации элемент управления ListView также может быть использован для вставки, редактирования и удаления информации. Как и элемент GridView, элемент управления ListView позволяет редактирование "по месту". То есть, пользователь может выбрать определенную запись на редактирование из отображенного списка записей, выполнить все необходимые изменения и затем обновить информацию. ListView также предоставляет функциональность вставки.

Принципы редактирования записей в ListView просты. Нам необходимо создать специальный шаблон для редактируемого элемента - данный шаблон, EditItemTemplate, используется для обработки элемента, редактируемого пользователем. В дополнение к этому нам необходимо добавить элемент управления Button, LinkButton или ImageButton (обычно в ItemTemplate), у которого свойство CommandName установлено в "Edit". При нажатии на данную кнопку выполняется постбэк и ListView повторно привязывается к своему источнику данных, при этом данный элемент обрабатывается при помощи EditItemTemplate.

ItemTemplate достаточно прост - просто добавьте LinkButton (Button или ImageButton) со свойством CommandName установленным в "Edit":

<ItemTemplate>
   <tr>
      <td>
         <asp:LinkButton ID="lnkEdit" runat="server" CommandName="Edit" Text="Edit" />
      </td>
      <td>
         <%# Eval("Name") %>
      </td>
      <td>
         <%# Eval("Telephone") %>
      </td>
   </tr>
</ItemTemplate> 

До того как мы создадим EditItemTemplate для ListView, существует усложняющее обстоятельство в нашей ситуации - нам необходим для начала  адрес. Вспомните, ведь отображаемые в ListView записи могут быть расположены на разных "уровнях" в XML-файле (т.е. различных филиалах/отделах). К примеру, при выборе определенного филиала или отдела из TreeView, ListView отображает не только сотрудников данного филиала или отдела, но и всех сотрудников дочерних филиалов и отделов. Необходимо иметь возможность определить правильный филиал или отдел,  которому принадлежит данный сотрудник, при сохранении измененных значений обратно в XML-файл.

Мы можем решить данную проблему путем запоминания адреса XPath XML-элемента Employee при загрузке его в ListView. Для этого нам необходимо добавить свойство в наш анонимный тип, возвращенный запросом LINQ. Текст в красном цвете XPathAddress: демонстрирует новый анонимный тип,

var query = from employeeElement in parentElement.Descendants("Employee")
            select new
            {
                Name = employeeElement.Attribute("name").Value,
                Telephone = employeeElement.Attribute("telephone").Value,
                XPathAddress = getXPathAddress(employeeElement)
            }; 

В дальнейшем мы установим данное значение в качестве свойства CommandArgument элемента LinkButton "Update" в EditItemTemplate элемента ListView.

Как вы можете заметить в указанном выше LINQ-запросе, XPathAddress было назначено значение, возвращенное методом getXPathAddress, которое нам необходимо создать в пределах класса с фоновым кодом ASP.NET-страницы. Метод итеративно пройдет по переданной структуре employeeElement к корневому элементу, тем самым выстраивая значение XPathAddress поднимаясь по дереву:

private string getXPathAddress(XElement element)
{
   XElement cElement = element;
   string xPath = "";

   // Мы итеративно пройдемся по структуре к корневому элементу
   // Цикл завершится в корневом элементе (мы не включаем корневой элемент
   // в адрес!!)
   while (cElement.Parent != null)
   {
       xPath = String.Format("/*[@id='{0}']",
               cElement.Attribute("id").Value)
                + xPath;

       cElement = cElement.Parent;
    }

    return xPath;

Теперь мы знаем выражение XPath для каждого объекта сотрудника и мы можем создать EditItemTemplate. Как вы могли бы уже заметить, свойству CommandArgument элемента LinkButton "Update" назначается значение XPathAddress , возвращенное LinqDataSource. Нам необходимо использовать данное значение в коде для обновления соответствующей записи сотрудника. Также обратите внимание на то, что вместо отображения значений имени и телефона сотрудника в Label мы используем веб-элемент управления TextBox.

<EditItemTemplate>
   <tr>
      <td>
         <asp:LinkButton ID="lnkUpdate" runat="server"   
            CommandName="XUpdate"
            CommandArgument="<%# Eval("XPathAddress") %>"
            Text="Update" />,
         <asp:LinkButton ID="lnkCancelEdit" runat="server"
            CommandName="Cancel"
            Text="Cancel" />
      </td>
      <td>
         <asp:TextBox ID="txtEditName" runat="server"
                   Text="<%# Eval("Name") %>" />
      </td>
      <td>
         <asp:TextBox ID="txtEditTelephone" runat="server"
                   Text="<%# Eval("Telephone") %>" />
      </td>
   </tr>
</EditItemTemplate> 

Вам наверняка интересно, почему мы использовали значение CommandName "XUpdate" вместо "Update". Если мы установим CommandName в "Update", то ListView попробует обновить изменения, автоматически вызвав метод Update элемента управления источником данных. Мы сопоставили данные собственноручно (в обработчике события Selecting элемента управления LinqDataSource), так что наш LinqDataSource в данном случае не может служить в качестве обновляющего источника. Поэтому нам необходимо самим написать метод, чтобы сохранить изменения.