SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

WebサービスをバインドしたDataGridViewでソート処理を実装する

ソート機能を実装したBindingListの作り方

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (91.5 KB)

ソート機能を利用するための準備

 それではソートができるように準備を始めましょう。DataGridViewでソート機能を簡単に利用するためには、まず次の2つのクラスを作成します。

  1. IComparerインターフェイスを実装したクラス
  2. BindingListを拡張したクラス

 IComparerインナーフェイスを実装したクラスではオブジェクトの比較ロジックを実装します。このクラスのオブジェクトをListオブジェクトのSortメソッドのパラメータとすることで、その比較ロジックを利用した並び替えを行うことができます。オブジェクトの比較ではオブジェクト自体にCompareメソッドを実装することも可能ですが、WSDLから生成されるオブジェクトに都度実装を行うのは手間がかかりますので、本稿ではIComparerインターフェイスを実装しています。

 BindingListはオブジェクトのリストをバインドできるクラスですので、このクラスを拡張することで手軽にオブジェクトの比較を実装できるようにします。

IComparerの実装

 ではまずIComparerインターフェイスを実装したSampleComparerクラスを作成してみましょう。

SampleComparer.vbの抜粋
Imports System
Imports System.ComponentModel
Imports System.Collections.Generic
Imports System.Reflection

Public Class SampleComparer(Of T)
    Implements IComparer(Of T)

    Private _direction As ListSortDirection 'ソートの向き(昇順/降順)
    Private _property As PropertyDescriptor 'ソート項目

    Public Sub New(ByVal prop As PropertyDescriptor, _
                   ByVal direction As ListSortDirection)
        Me._property = prop
        Me._direction = direction
    End Sub

    '同値の場合ゼロを返します。
    Public Function Compare(ByVal objX As T, ByVal objY As T) _
        As Integer Implements IComparer(Of T).Compare

        ' 比較対象のオブジェクトからクリックしたプロパティを取得します。
        Dim valX As Object = Me.GetPropValue(objX, Me._property.Name)
        Dim valY As Object = Me.GetPropValue(objY, Me._property.Name)

        'directionの値(昇順/降順)に応じて取得した値を比較します。
        If (Me._direction = ListSortDirection.Ascending) Then
            Return Me.CompareAsc(valX, valY)
        Else
            Return Me.CompareDesc(valX, valY)
        End If

    End Function

    '昇順で比較を行います。
    Private Function CompareAsc(ByVal valX As Object, _
                                ByVal valY As Object) As Integer
        Return valX.ToString.CompareTo(valY.ToString)
    End Function

    '降順で比較を行います。
    Private Function CompareDesc(ByVal valX As Object, _
                                 ByVal valY As Object) As Integer
        Return (Me.CompareAsc(valX, valY) * -1)
    End Function

    'プロパティ値を取得します。
    Private Function GetPropValue(ByVal val As T, _
                                  ByVal prop As String) As Object
        Dim propInfo As PropertyInfo = val.GetType.GetProperty(prop)
        Return propInfo.GetValue(val, Nothing)
    End Function

End Class

コンストラクタ

 コンストラクタでは比較対象となるプロパティを指定するPropertyDescriptorとソートの方向を指定するListSortDirectionをパラメータとしています。

 PropertyDescriptorはその名の通り、オブジェクトのプロパティについての情報定義です。プロパティのタイプ、値、ReadOnlyなどの情報を取得することができます。ここではプロパティの値を取得するために利用します。ListSortDirectionは並び替えの方向をあらわす列挙体でAscending(昇順)、Descending(降順)の値が定義されています。クリック時の昇順、降順ソートの方向を決めるために利用します。

メソッド

 比較ロジックを実装するCompareメソッドでは、第1パラメータと第2パラメータのオブジェクトからコンストラクタで指定された比較対象のプロパティ値を取得し、CompareToメソッドで大小比較を行っています。本稿では単純な例を挙げていますが、値がNothingであった場合の考慮など独自のロジックを実装することも可能です。

BindingListの拡張

 次にBindingListを継承したSortBindingListクラスを作成します。

SortableBindingList.vbの抜粋
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel

Public Class SortBindingList(Of T)
    Inherits BindingList(Of T)

    Private _isSorted As Boolean 'ソート済みか否かを識別します。
    ' ソート項目を保持します。
    Private _sortProperty As PropertyDescriptor
    ' ソート方向(昇順/降順)を保持します。
    Private _sortDirection As ListSortDirection

    ' リストをバインドします。
    Public Sub New(ByVal items As T())
        CType(Me.Items, List(Of T)).AddRange(items)
    End Sub

    'ソートが可能であることを公開します。
    'このプロパティがtrueで公開されないとソートが実行できません。
    Protected Overrides ReadOnly Property _
            SupportsSortingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    ' ソートを実行します。
    Protected Overrides Sub ApplySortCore( _
        ByVal prop As PropertyDescriptor, _
        ByVal direction As ListSortDirection)

        'ソートするためバインドされているリストを取得します。
        Dim items As List(Of T) = TryCast(MyBase.Items, List(Of T))

        'リストがあった場合、
        'Comparerを生成してソート項目と項目名を渡します。
        If (Not items Is Nothing) Then
            Dim sc As New SampleComparer(Of T)(prop, direction)
            items.Sort(sc)
            'ソート済みに設定します。
            Me._isSorted = True
        Else
            Me._isSorted = False
        End If

        'ソート結果、方向を保持しておきます。
        Me._sortProperty = prop
        Me._sortDirection = direction

        'リストが変更(ソート)されたことをイベント通知します。
        Me.OnListChanged(New ListChangedEventArgs( _
                                 ListChangedType.ItemMoved, prop))

    End Sub
End Class

コンストラクタ

 コンストラクタではパラメータにバインドを行うクラスのリストを受け取っています。ジェネリックリストとなっていますのでクラス定義をパラメータとして受け取り、オブジェクトをキャストしています。

プロパティ

 SupportsSortingCoreプロパティを実装し、ソート機能の利用可否を公開しています。Trueを返すように実装しないとソート機能を実行できません。

メソッド

 ApplySortCoreメソッドでソートのロジックを実装します。まず第1パラメータのPropertyDescriptorと第2パラメータのListSortDirectionを引数にして先ほど作成したSampleComparerを生成します。そしてバインドしておいたリストのSortメソッドのパラメータにSampleComparerオブジェクトを渡すことで並び替え処理を実行しています。

 ソートが完了したらListChangedイベントを発生させるために、OnListChangedメソッドを実行します。パラメータにはListChangedEventArgsを生成して渡しています。ListChangedEventArgsクラスのコンストラクタでは、第1パラメータにリスト項目が移動したことをあらわすListChangedType列挙体のItemMoved、第2パラメータには変更されたリストのプロパティを指定しています。

作成したBindingListを利用してWebサービスをDataGridViewへバインドする。

 バインドするには、BindingListを今回作成したSortableBindingListに入れ替えるだけです。ソートができるとヘッダーには矢印が表示され、ソートしている方向が示されます。

 それでは作成したSampleExtentionをWebサービスに適用させましょう。

SortBindingList適用したSampleForm.vbの抜粋
Public Class SampleForm

    Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button1.Click
        'SortBindingListを介してDataSouceにバインドした場合
        Me.BookBindingSource.DataSource = _
            New SortBindingList(Of BookProxy.Book) _
                (Me.BookService1.GetBookList)
    End Sub

End Class

実行例

 実行すると、ヘッダーをクリックする度にソートの昇順、降順が入れ替わります。このように作成したBindingListを適用するだけで簡単にソート機能を実装することができました。

サンプルアプリケーションの実行画面
サンプルアプリケーションの実行画面

まとめ

 本稿で説明したクラスを利用することで、オブジェクト配列でバインドされるデータに対しても簡単にソート機能を利用することができるようになりました。.NET Framework 2.0から登場したBindingListにはこれ以外にも検索機能を実装することなどができます。開発者の方々が使いやすいように拡張していくことで、より簡潔なコーディングで高機能な一覧表示を実装することができるようになるでしょう。

参考資料

  1. MSDN 『Web Services Developer Center』(日本語)
  2. MSDNライブラリ 『XML Web サービスの作成とアクセスに関するチュートリアル
  3. MSDNライブラリ 『IComparerインターフェイス
  4. MSDNライブラリ 『BindingListクラス
  5. MSDNライブラリ 『ListSortDirection列挙体
  6. MSDNライブラリ 『PropertyDescriptorクラス
  7. MSDNライブラリ 『ListChangedEventArgsクラス
  8. MSDNライブラリ 『ListChangedType列挙体

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 奥山 学(オクヤマ マナブ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1159 2007/04/10 08:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング