SelectedColumnSorterクラスを使う
これで、SortableListViewコントロールはSelectedColumnSorterクラスを使って特定の列によるソートを実行できる状態になりました。リスト1に、SortableListViewコントロールの重要なコード部分を示します。話を単純にするために、選択した列によるソート処理に関係のないコードは省略しています。
Imports System.ComponentModel <ToolboxBitmap(GetType(SortableListView), _ "tbxSortableListView")> _ Public Class SortableListView Inherits ListView Public Enum SortStyles SortDefault SortAllColumns SortSelectedColumn End Enum ' The current sort column for selected column sorting. Private m_SelectedColumn As Integer = -1 ' Whether we sort by all columns, one column, or not at all. Private m_SortStyle As SortStyles = SortStyles.SortDefault Public Property SortStyle() As SortStyles Get Return m_SortStyle End Get Set(ByVal value As SortStyles) ' If the current style is SortSelectedColumn, ' remove the column sort indicator. If m_SortStyle = SortStyles.SortSelectedColumn Then If m_SelectedColumn >= 0 Then Me.Columns(m_SelectedColumn).ImageKey = _ Nothing m_SelectedColumn = -1 End If End If ' Save the new value. m_SortStyle = value Select Case m_SortStyle Case SortStyles.SortDefault Me.ListViewItemSorter = Nothing Case SortStyles.SortAllColumns Me.ListViewItemSorter = New AllColumnSorter() Case SortStyles.SortSelectedColumn Me.ListViewItemSorter = _ New SelectedColumnSorter() End Select ' Resort. ' Me.Sort() End Set End Property ' Change the selected sort column. Protected Overrides Sub OnColumnClick( _ ByVal e As System.Windows.Forms.ColumnClickEventArgs) MyBase.OnColumnClick(e) If Me.SortStyle = SortStyles.SortSelectedColumn Then ' If this is the same sort column, switch the ' sort order. If e.Column = m_SelectedColumn Then If Me.Sorting = SortOrder.Ascending Then Me.Sorting = SortOrder.Descending Else Me.Sorting = SortOrder.Ascending End If End If ' Remove the image from the previous sort column. If m_SelectedColumn >= 0 Then Me.Columns(m_SelectedColumn).ImageKey = Nothing End If ' If we're not currently sorting, sort ascending. If Me.Sorting = SortOrder.None Then Me.Sorting = SortOrder.Ascending End If ' Save the new sort column and give it an image. m_SelectedColumn = e.Column If Me.Sorting = SortOrder.Descending Then Me.Columns(m_SelectedColumn).ImageKey = _ "sortDescending.bmp" Else Me.Columns(m_SelectedColumn).ImageKey = _ "sortAscending.bmp" End If ' Resort. Me.Sort() End If End Sub End Class
リスト1のコードには、名前空間System.ComponentModelのインポート後に、ToolboxBitmap属性と、SortableListViewコントロールがListViewを継承していることを示すClassステートメントが記されています。
<ToolboxBitmap(GetType(SortableListView), _ "tbxSortableListView")> _ Public Class SortableListView
SortableListViewコントロールでは、SortStyles列挙体を定義しています。これは、デフォルトのメソッドを使ったソート、すべての列によるソート、選択した列によるソートのどれを行うかを指定するためのものです。
Public Enum SortStyles SortDefault SortAllColumns SortSelectedColumn End Enum
また、ソートに用いる列のインデックスを保持するm_SelectedColumn変数も宣言されています。
SortStyleプロパティは、SortStyles列挙体の値の取得および設定に用います。Getプロシージャは、m_SortStyle変数の保持する値を返すだけのものです。
Public Property SortStyle() As SortStyles Get Return m_SortStyle End Get ...
一方、リスト1のSetプロシージャは、もう少し複雑な働きをします。まず、現時点でこのコントロールが「選択した列によるソート」を行おうとしているかどうかをチェックします。その場合は、その列に画像が一切表示されないように、列のImageKeyプロパティをNothingにして、ソート方向インジケータ(ソート方向を示す矢印)を取り除きます。
Set(ByVal value As SortStyles) ' If the current style is SortSelectedColumn, ' remove the column sort indicator. If m_SortStyle = SortStyles.SortSelectedColumn Then If m_SelectedColumn >= 0 Then Me.Columns(m_SelectedColumn).ImageKey = Nothing m_SelectedColumn = -1 End If End If ...
次にSetプロシージャは、新しいソート形式を保存したうえで、Select Caseステートメントによって適切な処理に分岐します。新しいソート形式がSortDefaultのときは、ListViewItemSorterプロパティにNothingが設定され、ListViewのデフォルトのソート処理がそのまま実行されることになります。ソート形式がSortAllColumnsのときは、ListViewItemSorterプロパティに新しいAllColumnSorterオブジェクト(後述)が設定されます。ソート形式がSortSelectedColumnのときは、ListViewItemSorterプロパティに新たなSelectedColumnSorterが設定されます。
... ' Save the new value. m_SortStyle = value Select Case m_SortStyle Case SortStyles.SortDefault Me.ListViewItemSorter = Nothing Case SortStyles.SortAllColumns Me.ListViewItemSorter = New AllColumnSorter() Case SortStyles.SortSelectedColumn Me.ListViewItemSorter = _ New SelectedColumnSorter() End Select ' Resort. ' Me.Sort() End Set End Property
Setプロシージャでは、この時点でSortableListViewコントロールのSortメソッドを呼び出し、この新たなソータを使って各アイテムを再ソートすることも可能です。ただし、このやり方は分かりにくいので、サンプルプログラムではその部分をコメントアウトしてメインプログラムからSortableListViewコントロールのSortメソッドを呼び出すようにしています。
SortableListViewコントロールで列のソートを行うために必要な最後の部分が、列ヘッダをユーザーがクリックするたびに呼び出されるOnColumnClickメソッドです。このメソッドのコードは、ベースクラスのOnColumnClickメソッドの呼び出しから始まります。続いて、現在のソート形式がSortSelectedColumnかどうかの判断を行います。
Protected Overrides Sub OnColumnClick( _ ByVal e As System.Windows.Forms.ColumnClickEventArgs) MyBase.OnColumnClick(e) If Me.SortStyle = SortStyles.SortSelectedColumn Then ' If this is the same sort column, switch the sort order. If e.Column = m_SelectedColumn Then If Me.Sorting = SortOrder.Ascending Then Me.Sorting = SortOrder.Descending Else Me.Sorting = SortOrder.Ascending End If End If ' Remove the image from the previous sort column. If m_SelectedColumn >= 0 Then Me.Columns(m_SelectedColumn).ImageKey = Nothing End If ' If we're not currently sorting, sort ascending. If Me.Sorting = SortOrder.None Then Me.Sorting = SortOrder.Ascending End If ' Save the new sort column and give it an image. m_SelectedColumn = e.Column If Me.Sorting = SortOrder.Descending Then Me.Columns(m_SelectedColumn).ImageKey = _ "sortDescending.bmp" Else Me.Columns(m_SelectedColumn).ImageKey = _ "sortAscending.bmp" End If ' Resort. Me.Sort() End If End Sub
直前に選択されていたのと同じ列をユーザーがクリックすると、上記のOnColumnClickメソッドのコードによってSortableListViewコントロールのソート方向が切り換わり、ソート方向インジケータが消去されます。現在のソート方向が選択されていない場合は、デフォルトである昇順が用いられます。
次に、新たにクリックされた列を選択した列として保存し、適切なソート方向のインジケータをその列に設定します。
SmallImageListプロパティにこうした画像を含むImageListコントロールを設定する必要があります。ImageListにおけるこれらの画像名は、「sortDescending.bmp」と「sortAscending.bmp」にします。画像のサイズを16x14ピクセルにすると最適な表示が得られるようです。 OnColumnClickのコードでは、最後にSortableListViewコントロールのSortメソッドを呼び出し、新たに選択した列とソート方向に従ってアイテムの再ソートを行います。
