Pull to refresh

asp.net: ListView с разных сторон

Reading time 7 min
Views 16K
Элемент управления ListView был представлен в .Net Framework 3.5 как замена устаревшему GridView. Новый элемент имеет более расширенный функционал, чем его предшественник, но в тоже время лишен некоторых внутренних механизмов, что впрочем целиком следствие из расширенной универсальности ListView. Среди отличий ListView и GridView можно назвать и гибкую настройку разметки, что позволяет выводить данные не только в табличном виде, но и вообще в любом каком пожелает программист. Благодаря шаблонам ItemTemplate, EditItemTemplate, InsertItemTeplate можно настроить внешний вид при любом из состояний ListView: редактировании или выборе элемента.

Я решил написать эту статью, чтобы поделиться опытом работы с ListView, привести некоторые способы решения общих задач, а также описать проблемы с которыми я столкнулся и которые у меня получилось решить не слишком красиво. Возможно, что при обсуждении статьи найдутся более гибкие решения описанных задач, чему я буду только рад.

Содержание

  • сортировка;
  • отказ от AlternatingTemplate;
  • выбор элемента;
  • объединение ячеек в колонке;
  • использование DropDownList для lookup при редактировании;
  • запрос на удаление;
  • редактирование и сохранение нескольких строк сразу;
  • сокрытие DataPager;
  • динамическая смена запросов для ListView.

Сортировка


В отличии от GridView, в ListView нет встроенной в редактор поддержки реализации механизма сортировки столбцов. На мой взгляд, отсутствие такой поддержки обусловлено тем, что ListView в отличии от GridView стал способен рендерить данные не только в табличном виде. Впрочем, даже при отсутствии механизма, добавление сортировки в таблицу ListView — это, наверное, самое легкое из того, что описано в этой статье. Рассмотрим реализацию на конкретном примере:
  <th class=«bankTd»>
    <asp:LinkButton ID=«sortBank» runat=«server» CommandName=«sort» CommandArgument=«Bank.shortName»
      Text=«Банк» />
  </th>
* This source code was highlighted with Source Code Highlighter.

Здесь CommandArgument=«Bank.shortName» указывает на то, какой столбец из источника данных сортировать.

Отказ от AlternatingItemTemplate


AlternatingItemTemplate предназначен для описания шаблона четных элементов списка. Это позволяет рендерить таблицы и другие типы наборов данных в красивом виде, например сделать так, что фоны строк данных в таблице будут чередоваться. В целом, отдельный шаблон — это конечно, хорошо, но чаще всего вся разница между строками в таблице заключается только в разном фоне или разных классах css. В этом случае объемный шаблон мне кажется избыточным и я предлагаю другое решение (подсмотренное в интернете):

  <ItemTemplate>
    <tr <%# Container.DataItemIndex % 2 == 0? "" : " class=\"alt\"" %>>

* This source code was highlighted with Source Code Highlighter.

В данном примере, вместо того, чтобы вводить в код AlternatingItemTemplate, я подставляю для четных строк особый css-класс. Кстати, в реальном проекте это позволяет сэкономить мне около 30 строк кода.

Выбор элемента


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

Есть такая табличка:


А вот как выглядит результат выбора данных в ней:


При использовании ajax работа с такой табличкой для конечного пользователя становится удобной и приятной. Живой пример можно попробывать тут. Нетрудно заметить, что после выбора данных пользователь получает доступ к расширенной информации и к дополнительным сервисам, в даном случае к печати данных, но тут может быть и редактирование, скрытие, удаление данных, в случае когда с данными работает их создатель или лицо имеющее право на данные операции.

Я не буду приводить в данном примере строк кода, потому что реализация не выходит за рамки обычного, все реализуется в SelectedItemTemplate, в котром вместо одной строки tr в данным случае выводится три: старая жирным шрифтом, расширенная информация и панель инструментов.

Объединение ячеек в колонке


Рассмотрим пример:



Весьма распространенная ситуация, когда необходимо объединить повторяющиеся по вертикали данные в одну ячейку. В GridView такая задача мной решалась через событие OnRowDataBound, в котором можно было получить доступ к текущей обрабатываемой строке и присвоить нужной ячейке нужный rowspan, а так же скрыть ненужные ячейки. В ListView, к сожалению, похожего инструмента нет. Более того на данный момент мне не известен аналогичный способ решения задачи. Предлагаемый мною способ строго говоря не реализует объединение ячеек в ListView, а только маскирует данные. Имеем такую разметку:
    <ItemTemplate>
      <tr runat=«server»>
        <td class=«bankTd» runat=«server» id=«bankName» style='<%# GetRowspanVisible(Eval(«Bank.shortName»).ToString()) %>'>
          <asp:HyperLink ID=«hlBank» runat=«server» Text='<%# Eval(«Bank.shortName») %>' NavigateUrl='test.aspx'></asp:HyperLink>
        </td>

...
* This source code was highlighted with Source Code Highlighter.

Здесь представлен кусочек tr в котором есть td, который и является целью объединения в случае повторяющихся данных. Предлагаю исходный текст метода GetRowspanVisible:
  private string _bankName = "";
  public string GetRowspanVisible(string bankName)
  {
    string result = «border: 0px; border-left: solid 1px #C0C0C0; font-size: 0px;»;

    if (Request.Browser.Browser == «IE»)
      result = «visibility: hidden; border: 0px; border-left: solid 1px #C0C0C0;»;

    if (_bankName != bankName)
    {
      _bankName = bankName;
      result = «border-top: solid 1px #C0C0C0; border-left: 1px; border-bottom: 0px;»;
    }

    return result;
  }
* This source code was highlighted with Source Code Highlighter.

Код не претендует на изящество. Я принимаю любые конструктивные предложения по его переделке. Сразу скажу, что завязка на стили была выбрана из-за того, что через классы такой подход лично у меня не заработал. Итак: как можно видеть, при обработке ячеек в столбце им присваивается разный стиль, в зависимости от того, что требуется: скрыть или показать. Таким образом, пользователь увидит данные только в первой ячейке, и пустые поля в следующих. Результат можно посмотреть на рисунке выше. Минусом такого решения, кроме всего прочего, является, понятно, привязка отображаемых данных к верхней границе, так как эти данные являются элементом верхней строки и не содержат rowspan.

Хотел бы заметить, что решение далеко от идеала, даже я сам это понимаю. Но продолжительные поиски и консультации с камрадами ни к чему не привели, другого решения пока на руках нет. Буду рад увидеть альтернативы и с удовольствием избавлюсь от текущей реализации. Пока же, что есть, то есть. Жду ваших комментариев.

Использование DropDownList для lookup при редактировании


В принципе задача простая, но я все равно решил привести решение в данной статье. В listview при редактировании требуется выводить DropDownList который бы заполнялся данными из стороннего источника справочних данных и биндился к нашему источнику данных для listview. Пример:



Решение, как я уже сказал, простое:
<asp:DropDownList ID=«ddlMetals» runat=«server» DataSourceID=«dsMetalDic» DataTextField=«name» DataValueField=«id» SelectedValue='<%# Bind(«metalId») %>'></asp:DropDownList>
* This source code was highlighted with Source Code Highlighter.

Здесь dsMetalDic — справочные данные, Bind(«metalId») — биндинг к нашему источнику данных для ListView.

Запрос на удаление


При удалении данных важно запросить у пользователя подтверждение на выполнение операции. При работе с ListView можно использовать следующее решение. Определим функцию javascript:
  >
    function OnDeleteClick()
    {
      return confirm('Удалить данные?');
    }
  
* This source code was highlighted with Source Code Highlighter.
Используем ее в элементе который отвечает за удаление данных:
<asp:LinkButton ID=«DeleteButton» runat=«server» CommandName=«Delete» Text=«Удалить» OnClientClick=«return OnDeleteClick();» />
* This source code was highlighted with Source Code Highlighter.

Редактирование и сохранение нескольких строк сразу


Порой необходимо вывести сразу весь набор данных состоящий из многих строк в режиме редактирования.


Решается эта задача через ItemTemplate и, в общем-то, это тривиальная задача. Другое дело как сохранить изменения во всех этих строках одним нажатием кнопки «Сохранить все»? Решение ниже:
    foreach (var item in lvEdit.Items)
    {
      lvEdit.UpdateItem(item.DataItemIndex, true);
    }
* This source code was highlighted with Source Code Highlighter.

Где lvEdit — это ListView.

Сокрытие DataPager


Когда страница в таблице одна, то отображать Pager не имеет смысла, поэтому будем скрывать. Трудность состоит в том, что в стандартном варианте реализации постраничной разбивки данных доступа к элементу DataPager нет. Но мы найдем его и скроем следующим нехитрым способом:
  protected void rlv_DataBound(object sender, EventArgs e)
  {
    ListView listView = sender as ListView;
    if (listView != null)
    {
      DataPager pager = listView.FindControl(«dp») as DataPager;
      if (pager != null)
        pager.Visible = pager.PageSize < pager.TotalRowCount;
    }
  }
* This source code was highlighted with Source Code Highlighter.

Здесь rlv_DataBound — это обработчик события OnDataBound у ListView, dp — имя нашего DataPager, который «встроен» через шаблоны в ListView.

Динамическая смена запросов для ListView


Сменить запрос для ListView не так уж и тривиально как может показаться когда мы используем LinqDataSource. Я знаю одно решение, которое приведу ниже:
  protected void dsResume_Selecting(object sender, LinqDataSourceSelectEventArgs e)
  {
    e.Result = Query;
  }
* This source code was highlighted with Source Code Highlighter.

Здесь dsResume_Selecting — это обработчик события OnSelecting у LinqDataSource.

Заключение


В этой статье я постарался осветить многие аспекты работы с ListView, привел несколько примеров и предложил несколько решений стандартных и не очень задач. Впрочем, я понимаю, что многие задачи могут быть решены другим способом, возможно даже более интересным. Жду конструктивных предложений, альтернативных решений, комментариев и указаний на ошибки, которые вы найдете. Статья писалась продолжительное время, прошу прощения за возможные ошибки при наборе текста.

PS: извините за возможные глюки в подсветке синтаксиса, этот вопрос сейчас решается с саппортом Хабра.
Tags:
Hubs:
+22
Comments 50
Comments Comments 50

Articles