none
DatagridView のソートのタイミングを変える方法を教えてください。(VB.NET 2005) RRS feed

  • 質問

  • 下記データーサンプル(マイクロソフト NorthWindow DB)から TEST.MDB(Access 2003) に「売り上げ」とういうテーブルを作成しました

    販売コード 支店 販売日 商品 個数 売上
    1 池袋 2009/10/05 13:54:30 オレンジジュース 5 \1,250
    2 上野 2009/10/05 0:20:11 コーヒー 10 \1,800
    3 上野 2009/10/05 1:05:18 グレープジュース 10 \2,500
    4 上野 2009/10/05 8:57:54 紅茶 10 \1,800
    5 新宿 2009/10/05 22:47:22 オレンジジュース 7 \1,750
    6 上野 2009/10/05 1:17:03 グレープジュース 6 \1,500
    7 渋谷 2009/10/05 14:56:41 コーヒー 4 \720
    8 渋谷 2009/10/05 19:54:55 紅茶 7 \1,260
    9 品川 2009/10/05 21:51:47 オレンジジュース 8 \2,000
    10 品川 2009/10/05 5:51:16 グレープジュース 3 \750
    11 上野 2009/10/06 0:22:37 グレープジュース 3 \750
    12 新宿 2009/10/06 19:10:24 オレンジジュース 2 \500

    ==================================================

    VB.NET 2005 にて 新しいプロジェクトを作成

    Windows フォーム Form1 上に メニューからデータ/新しいデータ接続 を実行し

    先に作成した MDB に接続してください。


    データーソースのウインドウより テーブル「売り上げ」をForm1 上に
    ドラッグ&ドロップすると 自動的にデータグリッドの配置がされます。

    この状態からForm1 を実行してデータを編集します。

    初期状態は 販売コード で昇順でソートされています。

    「支店」のヘッダーをクリックして 「支店」で昇順になるようにします。

    販売コード 8番 のデータ 支店:渋谷 → 池袋 にします。 セルを移動しても ソートされません

    編集直後では 支店 でのソートは起こりません。 行を変更、つまり
    他の行をクリックしたときに ソートが起こります。

    この他の行をクリックしたときに ソートが起こるのではなく ヘッダーの支店をクリックした場合のみソート
    をさせるということは 可能でしょうか?

    =======================================<実装したコード>============================

    Public Class Form1

        Private Sub 売上テーブルBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 売上テーブルBindingNavigatorSaveItem.Click
            Me.Validate()
            Me.売上テーブルBindingSource.EndEdit()
            Me.売上テーブルTableAdapter.Update(Me.TESTDataSet.売上テーブル)

        End Sub

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            'TODO: このコード行はデータを 'TESTDataSet.売上テーブル' テーブルに読み込みます。必要に応じて移動、または削除をしてください。
            Me.売上テーブルTableAdapter.Fill(Me.TESTDataSet.売上テーブル)

        End Sub
    End Class

    ==============================================================================

    以上、よろしくお願いします。

    • 編集済み MYNOBU 2010年1月3日 18:15
    2009年12月25日 14:54

回答

  • 可能か不可能かでいえば、かなり面倒な手段を使えば実現は可能です。
    以下の内容でわからないのでしたら、特殊な並べ替えはあきらめたほうがいいですよ。

    DataGridViewは並べ替えが指定されると、データソースを並べ替えしてあるリストを作って、それにアクセスしているようです。
    あるいははじめから並び替えされているデータソース(DataViewやBindingSource)にアクセスします。
    並べ替えられたデータにアクセスするため、常に並べ替えた状態でしか表示できません。
    ですから通常の方法では希望されている動作は出来ません。

    案1
    DataTableに非表示のDataColumnを追加しておき、このソート用DataColumでソートを指定する。
    表示されているDataGridViewColumnのSortModeはNotSortableかProgrammaticにしておきます。
    DataGridViewのColumnHeaderMouseClickイベントのタイミングでのみこのDataColumnの値を新しい値に書き換えます。
    デメリットとして、DataTableに 列が増えてしまうのと、RowStateが変化してしまう問題がある。

    案2
    DataGridViewとDataTabeの間にBindingSourceを入れ、さらにIBindingListViewを入れて、
    「DataGridView.DataSource <-> カスタムIBindingListView <-> BindingSource <-> DataTable」
    という関係にします。
    表示されているDataGridViewColumnのSortModeはNotSortableかProgrammaticにしておきます。
    カスタムIBindingListViewはBindingSourceの並べ替え直後の並び順を保持するListを内部に持たせておき、DataGridViewから行データを要求されたら、この内部ListのIndexを使って取り出すようにします。
    DataGridViewのColumnHeaderMouseClickイベントのタイミングでBindingSourceのSortを変更し、さらにカスタムIBindingListViewの内部ListをBindingSourceの新しい並びで更新します。
    デメリットとして、実装する量が多くなるのと行追加削除の処理を同期させるのが面倒。

    案3
    DataGridViewをVirtualModeにして自分で並べ替え処理を管理する。
    デメリットは表示行管理が面倒。

    #案2をためしに実装してテストして並べ替えが遅延できることは確認済みですが、提示できる完成度になっていないのでソースは貼りません。
    • 編集済み gekkaMVP 2009年12月29日 2:08 行と列の書き間違い訂正
    • 回答としてマーク 菊地俊介 2010年1月18日 9:45
    2009年12月26日 15:49
  • gekkaさんも書かれていますが、残念ながら簡単には実現できません。参考になりそうなページをご紹介しておきます。

    DataGridView: how to stop / cancel sorting
    http://social.msdn.microsoft.com/Forums/en/winformsdatacontrols/thread/ce630093-ed6c-4b54-9a98-67a2e8dc112b

    DataGridView - suppressing auto-sort / re-sort
    http://social.msdn.microsoft.com/Forums/en/winforms/thread/91d65e58-60b3-4367-a580-07cdf7574eb3


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク 菊地俊介 2010年1月18日 9:45
    2009年12月27日 9:03
    モデレータ

すべての返信

  • 可能か不可能かでいえば、かなり面倒な手段を使えば実現は可能です。
    以下の内容でわからないのでしたら、特殊な並べ替えはあきらめたほうがいいですよ。

    DataGridViewは並べ替えが指定されると、データソースを並べ替えしてあるリストを作って、それにアクセスしているようです。
    あるいははじめから並び替えされているデータソース(DataViewやBindingSource)にアクセスします。
    並べ替えられたデータにアクセスするため、常に並べ替えた状態でしか表示できません。
    ですから通常の方法では希望されている動作は出来ません。

    案1
    DataTableに非表示のDataColumnを追加しておき、このソート用DataColumでソートを指定する。
    表示されているDataGridViewColumnのSortModeはNotSortableかProgrammaticにしておきます。
    DataGridViewのColumnHeaderMouseClickイベントのタイミングでのみこのDataColumnの値を新しい値に書き換えます。
    デメリットとして、DataTableに 列が増えてしまうのと、RowStateが変化してしまう問題がある。

    案2
    DataGridViewとDataTabeの間にBindingSourceを入れ、さらにIBindingListViewを入れて、
    「DataGridView.DataSource <-> カスタムIBindingListView <-> BindingSource <-> DataTable」
    という関係にします。
    表示されているDataGridViewColumnのSortModeはNotSortableかProgrammaticにしておきます。
    カスタムIBindingListViewはBindingSourceの並べ替え直後の並び順を保持するListを内部に持たせておき、DataGridViewから行データを要求されたら、この内部ListのIndexを使って取り出すようにします。
    DataGridViewのColumnHeaderMouseClickイベントのタイミングでBindingSourceのSortを変更し、さらにカスタムIBindingListViewの内部ListをBindingSourceの新しい並びで更新します。
    デメリットとして、実装する量が多くなるのと行追加削除の処理を同期させるのが面倒。

    案3
    DataGridViewをVirtualModeにして自分で並べ替え処理を管理する。
    デメリットは表示行管理が面倒。

    #案2をためしに実装してテストして並べ替えが遅延できることは確認済みですが、提示できる完成度になっていないのでソースは貼りません。
    • 編集済み gekkaMVP 2009年12月29日 2:08 行と列の書き間違い訂正
    • 回答としてマーク 菊地俊介 2010年1月18日 9:45
    2009年12月26日 15:49
  • gekkaさんも書かれていますが、残念ながら簡単には実現できません。参考になりそうなページをご紹介しておきます。

    DataGridView: how to stop / cancel sorting
    http://social.msdn.microsoft.com/Forums/en/winformsdatacontrols/thread/ce630093-ed6c-4b54-9a98-67a2e8dc112b

    DataGridView - suppressing auto-sort / re-sort
    http://social.msdn.microsoft.com/Forums/en/winforms/thread/91d65e58-60b3-4367-a580-07cdf7574eb3


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク 菊地俊介 2010年1月18日 9:45
    2009年12月27日 9:03
    モデレータ
  • ご丁寧な解説、ありがとうございます。

    難しいということがわかりました。

    Datasourceを指定しない場合は 他の行をクリックしてソートが起こらないことはわかっていたので おそらく Dataview みたいな感じで

    レコードソース側の問題ではないかとおもっていました。

    どなたかが 汎用的なソートができる Dtagridviewの別クラス を提示していないものか探したけれでも 見当たりませんでした。


    大変、参考になりました。
    2009年12月27日 16:34
  • いつも、お世話になっております。

    英語の文章とソースコードを理解するのに少し、時間がかかりそうです。

    参考資料、どうもありがとうございます。
    2009年12月27日 16:36
  • BindingSourceのRaiseListChangedEventsをfalseにするとご希望の動作になるようです。
    副作用もありそうですが単独でDataGridViewだけを使うのならいけそうな気もします。
    即時に並び変わるのはListChangedType.ResetのタイプでListChangedイベントがでいちいち起こるからなのです。

    http://www.mahoroba.ne.jp/~mw_ken
    2009年12月29日 15:09
  • 三輪の牛 ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルさま

    ご返答ありがとうございます。

    >>BindingSourceのRaiseListChangedEventsをfalseにするとご希望の動作になるようです。

    を試しましたが うまくゆきませんでした。

    データ入力後、他の行をクリックしても変わっていないように見えているだけで実際はソートされています。

    たとえば、当初の質問の例題のとおりに入力した場合、入力後はソートされていません(見かけだけ)。 でもスクロールしてゆくと

    あれ! やはりソートされています。
    2009年12月30日 12:08
  • おっしゃるとおり見かけだけでした。
    済みませんでした。面倒な方法をとるしかなさそうです。

    http://www.mahoroba.ne.jp/~mw_ken
    2009年12月30日 14:37
  • 皆様、こんにちは。

    gekkaさん、trapemiyaさん、三輪の牛さん、回答ありがとうございます。

    MYNOBUさん、フォーラムのご利用ありがとうございます。
    簡単にご希望の動作を実現するする方法はないようですね。
    参考になる情報と思われたため、gekkaさん、trapemiyaさんの回答へ回答マークをつけさせていただきました。

    今後とフォーラムをよろしくお願いします。
    それでは!
    2010年1月18日 9:48