Резюме
В статье описывается, как реализовать сортировку элементов в элементе
управления ListView в .NET Microsoft на основе столбца, выбираемого
щелчком мыши. (13 печатных страниц)
Содержание
Введение
Элемент управления ListView хорошо подходит для отображения
информации о файловой системе и данных из XML-файла или базы данных.
Элемент управления ListView обычно используется, чтобы отобразить
графический значок, представляющий элемент, а также текст элемента.
Кроме того, элемент управления ListView может использоваться для
отображения дополнительной информации об элементе в подэлементе. В
частности, если элемент управления ListView отображает список файлов,
элемент управления ListView можно сконфигурировать так, чтобы он
отображал дополнительную информацию, например, размер файла и атрибуты
как подэлементы. Чтобы отобразить информацию о подэлементе в элементе
управления ListView, необходимо установить свойство View на
View.Details. Кроме того, требуется создать объекты ColumnHeader и
присвоить их свойству Columns элемента управления ListView. После
установки этих свойств элементы отображаются в строках и столбцах как в
элементе управления DataGrid. Благодаря возможности отображать элементы
этим способом элемент управления ListView становится быстрым и простым
решением для отображения данных из источника данных любого типа.
Сортировка для элемента управления ListView предоставлена с помощью
его свойства Sorting. Оно позволяет определить тип сортировки,
применяемой к элементам. Это является великолепной возможностью при
сортировке только по элементам. Если необходимо сортировать по
подэлементам, следует использовать пользовательские возможности
сортировки элемента управления ListView. В этой статье будет показано,
как выполнить пользовательскую сортировку в элементе управления ListView
и обработать специальные, зависящие от типа данных условия при
сортировке.
Пользовательские возможности сортировки элемента управления ListView
Элемент управления ListView позволяет использовать сортировку,
отличную от сортировки, предоставляемой свойством Sorting. Когда элемент
управления ListView сортирует элементы с помощью свойства Sorting, он
использует класс, реализующий интерфейс System.Collections.IComparer.
Этот класс предоставляет возможности сортировки, используемые для
сортировки каждого элемента. Чтобы сортировать по подэлементам,
необходимо создать собственный класс, реализующий интерфейс IComparer,
который в свою очередь реализует сортировку, требующуюся для элемента
управления ListView. Этот класс определяется конструктором, указывающим
столбец, по которому сортируется элемент управления ListView. После
создания этого класса обычно в качестве вложенного класса формы
необходимо создать экземпляр этого класса и присвоить его свойству
ListViewItemSorter элемента управления ListView. Оно идентифицирует
пользовательский класс сортировки, используемый элементом управления
ListView при вызове метода Sort. Метод Sort выполняет фактическую
сортировку элементов ListView.
Сортировка по возрастанию
В следующих разделах приводится пример сортировки в элементе
управления ListView по его подэлементам. Этот пример иллюстрирует
элементы сортировки в элементе управления ListView по возрастанию.
Сортировка по возрастанию или по убыванию рассматривается в следующем
разделе этой статьи. Цель статьи состоит в демонстрации основных
требований для пользовательской сортировки в элементе управления
ListView.
Инициализация элемента управления
Для начала работы создайте экземпляр элемента управления ListView и
добавьте его в форму. После этого к элементу управления ListView
добавьте элементы с помощью свойства Items. Число добавляемых элементов
не ограничено; необходимо только убедиться, что текст каждого элемента
уникален. При создании элементов добавьте по два подэлемента для каждого
элемента. Первый подэлемент должен содержать числовую информацию, а
второй - информацию о дате. Следующая таблица является примером того,
как эта информация может выглядеть в элементе управления ListView.
Элемент |
Подэлемент 1 |
Подэлемент 2 |
Alpha |
1.0 |
4/5/1945 |
Charlie |
3.5 |
1/9/1920 |
Bravo |
2.4 |
12/8/1930 |
Создайте два объекта ColumnHeader и присвойте их свойству Columns
элемента управления ListView. Установите свойство View на View.Details.
Обработка события ColumnClick
Чтобы определить набор подэлементов для сортировки, необходимо знать,
когда пользователь щелкает по заголовку столбца для подэлемента. Для
этого требуется создать метод обработки события ColumnClick элемента
управления ListView. Поместите метод обработки события как член формы и
проверьте, что ему соответствует код, подобный показанному ниже.
'Visual Basic
Private Sub listView1_ColumnClick(sender As Object, e
As System.Windows.Forms.ColumnClickEventArgs)
End Sub
//C#
private void listView1_ColumnClick(object sender,
System.Windows.Forms.ColumnClickEventArgs e)
{
}
Соедините метод обработки события с элементом управления ListView,
добавив код к конструктору формы, как проиллюстрировано в следующем
примере.
'Visual Basic
AddHandler listView1.ColumnClick, AddressOf Me.listView1_ColumnClick
//C#
this.listView1.ColumnClick +=
new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick);
Добавьте следующий код к методу обработки события ColumnClick.
'Visual Basic
' Установка свойства ListViewItemSorter на новый объект ListViewItemComparer.
Me.listView1.ListViewItemSorter = New ListViewItemComparer(e.Column)
' Вызов метода сортировки для ручной сортировки.
listView1.Sort()
//C#
// Установка свойства ListViewItemSorter на новый объект
// ListViewItemComparer.
this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column);
// Вызов метода сортировки для ручной сортировки.
listView1.Sort();
Код, добавленный к методу обработки события, устанавливает свойство
ListViewItemSorter элемента управления ListView с помощью нового
экземпляра класса ListViewItemComparer (который будет определен в
следующем разделе) и присваивает столбец, выбираемый в данных момент
щелчком мыши. Выбираемый щелчком мыши столбец передается как часть
параметров события. После установки свойства ListViewItemSorter
вызывается метод Sort, выполняющий ручную сортировку.
Создание класса ListViewItemComparer
Как упоминалось ранее, ключом к пользовательской сортировке в
элементе управления ListView является создание класса, реализующего
интерфейс System.Collections.IComparer. Именно этот класс предоставляет
возможность сортировки элементов. В этом примере класс
ListViewItemComparer определен и добавлен как вложенный класс данной
формы. ListViewItemComparer выполняет основную сортировку по возрастанию
для указанного столбца, который передается в конструктор класса.
Добавьте к классу Form следующее определение и проверьте, что он
правильно вложен в форме.
'Visual Basic
' Реализация ручной сортировки элементов по столбцу.
Class ListViewItemComparer
Implements IComparer
Private col As Integer
Public Sub New()
col = 0
End Sub
Public Sub New(column As Integer)
col = column
End Sub
Public Function Compare(x As Object, y As Object) As Integer _
Implements System.Collections.IComparer.Compare
Dim returnVal as Integer = -1
returnVal = [String].Compare(CType(x, _
ListViewItem).SubItems(col).Text, _
CType(y, ListViewItem).SubItems(col).Text)
Return returnVal
End Function
End Class
//C#
// Реализация ручной сортировки элементов по столбцу.
class ListViewItemComparer : IComparer {
private int col;
public ListViewItemComparer() {
col=0;
}
public ListViewItemComparer(int column)
{
col=column;
}
public int Compare(object x, object y)
{
int returnVal = -1;
returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
((ListViewItem)y).SubItems[col].Text);
return returnVal;
}
}
Сортировка выполняется в требуемом методе интерфейса IComparer,
называющемся Compare. Этот метод принимает два объекта как параметры, в
которых будут содержаться два сравниваемых элемента. Когда метод Sort
вызывается в методе обработки события ColumnClick элемента управления
ListView, метод Sort использует объект ListViewItemComparer,
определенный и присвоенный свойству ListViewItemSorter, и вызывает его
метод Compare. Когда объект ListViewItemComparer создан, он
присваивается индексу столбца, выбранного щелчком мыши. Этот индекс
столбца используется для обращения к подэлементам столбца, который
требуется отсортировать. Затем подэлементы передаются в метод
String.Compare, который сравнивает элементы и возвращает один из трех
результатов. Если элемент в параметре x меньше элемента в параметре y,
возвращается значение меньше нуля. Если элементы идентичны, возвращается
нуль. Наконец, если элемент в параметре x больше элемента в параметре y,
возвращается значение больше нуля. Значение, возвращенное методом
Compare, передается назад в метод Sort, определяющий местоположение
каждого сравниваемого элемента в столбце. Метод Sort вызывает метод
Compare требуемое число раз, чтобы отсортировать все подэлементы в
выбранном столбце.
Пример, приведенный выше, завершен. Если выполнить пример и щелкнуть
по заголовкам столбцов элемента управления ListView, элементы будут
отсортированы соответствующим образом в алфавитном или числовом порядке.
Единственный столбец, который не будет отсортирован должным образом, -
это столбец, содержащий информацию о дате. Сортировка столбца дат
рассматривается далее в этой статье.
Этот пример демонстрирует основные компоненты, необходимые для
выполнения основной сортировки элементов вручную в элементе управления
ListView. В следующем разделе этот пример расширяется, предоставляя
возможности сортировки по возрастанию и убыванию.
Сортировка по возрастанию или по убыванию
Пользователям элемента управления ListView потребуется сортировка
элементов по возрастанию и убыванию. Чтобы облегчить эту задачу, в
предыдущий пример необходимо внести некоторые изменения, чтобы метод
Compare мог идентифицировать элементы для сортировки.
Изменения в форме
Как правило, чтобы переключиться между сортировкой по возрастанию и
убыванию, необходимо щелкнуть заголовок столбца еще раз. Пользователи
ожидают, что при первом щелчке заголовка столбца происходит сортировка,
а при последующем щелчке - изменение порядка сортировки. Предыдущий
пример кода должен уметь определять, что на столбце щелкнули больше
одного раза. Для этого добавьте закрытую переменную типа integer к
классу Form. Эта переменная хранит последний столбец, который был выбран
щелчком мыши. Метод обработки события ColumnClick использует эту
переменную, чтобы сравнить последний столбец со столбцом, выбираемым
щелчком мыши в данный момент, и определить, совпадают столбцы или нет.
Добавьте следующее определение члена к классу Form.
'Visual Basic
Dim sortColumn as Integer = -1
//C#
private int sortColumn = -1;
Изменения в методе обработки события ColumnClick
В метод обработки события ColumnClick, определенный в предыдущем
примере, необходимо внести изменения, чтобы он отслеживал столбец,
выбранный щелчком мыши, и текущий порядок сортировки. Добавьте следующий
код, заменив код в методе обработки события ColumnClick, созданном в
предыдущем примере.
'Visual Basic
Private Sub listView1_ColumnClick(sender As Object, e As
System.Windows.Forms.ColumnClickEventArgs)
' Определение того, совпадает ли столбец с последним выбранным столбцом.
If e.Column <> sortColumn Then
' Установка сортировки нового столбца.
sortColumn = e.Column
' Установка порядка сортировки "по возрастанию" как порядка по
' умолчанию.
listView1.Sorting = SortOrder.Ascending
Else
' Определение и последующее изменение последнего порядка сортировки.
If listView1.Sorting = SortOrder.Ascending Then
listView1.Sorting = SortOrder.Descending
Else
listView1.Sorting = SortOrder.Ascending
End If
End If
' Вызов метода ручной сортировки.
listView1.Sort()
' Установка свойства ListViewItemSorter на новый объект
' ListViewItemComparer.
listView1.ListViewItemSorter = New ListViewItemComparer(e.Column, _
listView1.Sorting)
End Sub
//C#
private void listView1_ColumnClick(object sender,
System.Windows.Forms.ColumnClickEventArgs e)
{
// Определение того, совпадает ли столбец с последним выбранным столбцом.
if (e.Column != sortColumn)
{
// Установка сортировки нового столбца.
sortColumn = e.Column;
// Установка порядка сортировки "по возрастанию" как порядка по
// умолчанию.
listView1.Sorting = SortOrder.Ascending;
}
else
{
// Определение и последующее изменение последнего порядка сортировки.
if (listView1.Sorting == SortOrder.Ascending)
listView1.Sorting = SortOrder.Descending;
else
listView1.Sorting = SortOrder.Ascending;
}
// Вызов метода ручной сортировки.
listView1.Sort();
// Установка свойства ListViewItemSorter на новый объект
// ListViewItemComparer.
this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column,
listView1.Sorting);
}
В этом коде добавлены некоторые логические операции перед установкой
свойства ListViewItemSorter и вызовом метода Sort. Добавленный код
определяет, совпадает ли элемент, на который щелкают в данный момент, с
последним столбцом, выбранным щелчком мыши. Если они не совпадают,
устанавливается переменная sortColumn, и свойство Sorting присваивается
значению SortOrder.Ascending. Если переменная sortColumn и выбираемый в
данный момент столбец совпадают, свойство Sorting изменяется на
противоположный порядок сортировки. В этом примере свойство Sorting
используется как способ определения порядка сортировки элементов.
Поскольку для сортировки элементов используется пользовательский класс
Comparer, установка свойства Sorting не влияет на операцию сортировки.
Она используется просто как переменная в примере.
После определения порядка сортировки внесите последнее изменение в
код метода обработки события ColumnClick: добавьте дополнительное
значение параметра к созданию объекта ListViewItemComparer, который
необходимо присвоить свойству ListViewItemSorter. Далее в этом примере
показано, что класс ListViewItemComparer содержит новый параметр,
определяющий порядок сортировки. Значение свойства ListView.Sorting
используется, чтобы присвоить значение параметру.
Изменения в классе ListViewItemComparer
Чтобы этот пример мог сортировать по возрастанию или по убыванию,
последние изменения необходимо внести в класс ListViewItemComparer.
Добавленный код содержит логические операции, требуемые для сравнения
элементов в любом режиме сортировки. Добавьте следующий код, заменив
код, определенный для ListViewItemComparer в предыдущем примере.
'Visual Basic
' Реализация ручной сортировки элементов по столбцам.
Class ListViewItemComparer
Implements IComparer
Private col As Integer
Private order as SortOrder
Public Sub New()
col = 0
order = SortOrder.Ascending
End Sub
Public Sub New(column As Integer, order as SortOrder)
col = column
Me.order = order
End Sub
Public Function Compare(x As Object, y As Object) As Integer _
Implements System.Collections.IComparer.Compare
Dim returnVal as Integer = -1
returnVal = [String].Compare(CType(x, _
ListViewItem).SubItems(col).Text, _
CType(y, ListViewItem).SubItems(col).Text)
' Определение того, является ли порядок сортировки порядком "по
' убыванию".
If order = SortOrder.Descending Then
' Изменение значения, возвращенного String.Compare, на
' противоположное.
returnVal *= -1
End If
Return returnVal
End Function
End Class
//C#
// Реализация ручной сортировки элементов по столбцам.
class ListViewItemComparer : IComparer {
private int col;
private SortOrder order;
public ListViewItemComparer() {
col=0;
order = SortOrder.Ascending;
}
public ListViewItemComparer(int column, SortOrder order)
{
col=column;
this.order = order;
}
public int Compare(object x, object y)
{
int returnVal= -1;
returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
((ListViewItem)y).SubItems[col].Text);
// Определение того, является ли порядок сортировки порядком "по
// убыванию".
if(order == SortOrder.Descending)
// Изменение значения, возвращенного String.Compare, на
// противоположное.
returnVal *= -1
return returnVal;
}
}33
Этот код добавляет к конструктору параметр порядка сортировки и
создает закрытую переменную, хранящую это значение. В код для метода
Compare внесены изменения, позволяющие определить, является ли порядок
сортировки порядком "по убыванию". Если да, то значение, возвращенное
методом String.Compare, умножается на -1 и становится противоположным
значению, возвращенному методом Compare.
Выполните код и щелкните на каком-либо столбце. Столбец сортируется
по возрастанию. Щелкните на том же столбце еще раз, и он будет
отсортирован по убыванию. Столбец дат снова не будет отсортирован
должным образом, поскольку он сортируется как строка, а не как дата. В
следующем разделе для завершения примера добавим к нему функциональные
возможности сортировки по дате или строке в зависимости от типа данных.
Сортировка дат
Данные, помещенные в элемент управления ListView как элемент,
отображаются и хранятся как текст. Это облегчает сортировку с помощью
метода String.Compare в классе IComparer. Метод String.Compare сортирует
как буквенные символы, так и числа. Однако некоторые типы данных
невозможно отсортировать правильно с помощью String.Compare, например,
информацию о дате и времени. По этой причине в структуре System.DateTime
имеется метод Compare так же, как и в классе String. Этот метод
позволяет выполнить тот же тип сортировки в хронологическом порядке. В
этом разделе необходимо изменить только метод Compare для правильной
сортировки дат.
Добавьте следующий код, заменив код для метода Compare класса
ListViewItemComparer, определенного в предыдущем примере.
'Visual Basic
Public Function Compare(ByVal x As Object, ByVal y As Object) As
Integer Implements System.Collections.IComparer.Compare
Dim returnVal As Integer
' Определение того, принадлежат ли сравниваемые данные типу "дата".
Try
' Анализ двух обрабатываемых объектов как параметра DateTime.
Dim firstDate As System.DateTime = DateTime.Parse(CType(x, _
ListViewItem).SubItems(col).Text)
Dim secondDate As System.DateTime = DateTime.Parse(CType(y, _
ListViewItem).SubItems(col).Text)
' Сравнение двух дат.
returnVal = DateTime.Compare(firstDate, secondDate)
' Если ни один из сравниваемых объектов не имеет допустимый
' формат даты, сравнение как строки.
Catch
' Сравнение двух элементов как строк.
returnVal = [String].Compare(CType(x, _
ListViewItem).SubItems(col).Text,
CType(y,ListViewItem).SubItems(col).Text)
End Try
' Определение того, является ли порядок сортировки порядком "по
' убыванию".
If order = SortOrder.Descending Then
' Изменение значения, возвращенного String.Compare, на
' противоположное.
returnVal *= -1
End If
Return returnVal
End Function
//C#
public int Compare(object x, object y)
{
int returnVal;
// Определение того, принадлежат ли сравниваемые данные типу "дата".
try
{
// Анализ двух обрабатываемых объектов как параметра DateTime.
System.DateTime firstDate =
DateTime.Parse(((ListViewItem)x).SubItems[col].Text);
System.DateTime secondDate =
DateTime.Parse(((ListViewItem)y).SubItems[col].Text);
// Сравнение двух дат.
returnVal = DateTime.Compare(firstDate, secondDate);
}
// Если ни один из сравниваемых объектов не имеет допустимый
// формат даты, сравнение как строки.
catch
{
// Сравнение двух элементов как строк.
returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
((ListViewItem)y).SubItems[col].Text);
}
// Определение того, является ли порядок сортировки порядком "по
// убыванию".
if (order == SortOrder.Descending)
// Изменение значения, возвращенного String.Compare, на
// противоположное.
returnVal *= -1;
return returnVal;
}
Код, заменивший предыдущую версию метода Compare, начинается с
преобразования параметров x и y в объекты DateTime. Это извлечение
выполняется в блоке try-catch и позволяет перехватить исключения,
которые могут произойти при выполнении преобразования этих двух
сравниваемых элементов в объекты DateTime. Если исключение произошло,
оно сообщает коду, что преобразуемый тип не является допустимой датой
или временем и может быть отсортирован методом String.Compare. Если эти
два типа являются датами, они сортируются с помощью метода
DateTime.Compare.
Выполните эту новую версию примера кода и щелкните на любом столбце.
Будет видно, что подэлементы, включая столбец дат, сортируются должным
образом. Теперь элемент управления ListView, рассмотренный в примере,
может обрабатывать все типы отображаемых данных должным образом.
Заключение
Элемент управления ListView может отображать данные несколькими
способами. Он может использоваться, чтобы отобразить отдельные элементы,
а также элементы, содержащие информацию о подэлементах. Используя
возможности сортировки элемента управления ListView, разработчик может
также предоставить пользователям возможность сортировать элементы в
элементе управления ListView на основе этих подэлементов независимо от
типа предоставленных данных. Возможность сортировать элементы и их
подэлементы позволяет приложению вести себя так же, как Microsoft®
Windows® Explorer и другие знакомые
пользователям приложения, предоставляющие отображение данных в ListView
и сортировку его содержания.