Silverlight 使い始めました。マウスホイールでスクロールできないなんて……。以下、ほとんど文章だけなんでわかりにくいと思いますが。
DataGridをマウスホイール対応するには、以前kazukiさんが書かれていますね。[C#][Silverlight]DataGridのマウスホイールでのスクロール その2 この方法は選択行を変える方法でしたが、もっと自然な動作させる実装が、Silverlight2.0 - DataGridをホイールマウススクロールに対応させる - PYRO :: Blog にありました。すっごいぬるぬる動くよ!
後者は、LoadingRowとUnloadingRowイベントにより現在表示されている行の最大と最小のインデックス値を保持しておいて、スクロール時にインデックス±1の行へスクロールするという手法です。
が、こっちもソートすると、うまく動いてくれませんでした。最初はソートされてもインデックス値が変わらないのかなと思ったのですが、きちんとインデックス値は変わっていました。ソート時に表示されている行だけLoadingRow、UnloadingRowイベントが発生しますが、昇順 or 降順に発生しないので最大と最小の行のインデックス値がおかしくなってしまうっぽい。
そこで、LoadingRow、UnloadingRowイベントで現在表示されている行のインデックスすべてを保持するように変えてみました。
Private indexs As New List(Of Integer)
Private Shadows Sub OnLoadingRow(ByVal sender As Object, ByVal args As DataGridRowEventArgs)
If Not indexs.Contains(args.Row.GetIndex) Then
indexs.Add(args.Row.GetIndex)
End If
End Sub
Private Shadows Sub OnUnloadingRow(ByVal sender As Object, ByVal args As DataGridRowEventArgs)
If indexs.Contains(args.Row.GetIndex) Then
indexs.Remove(args.Row.GetIndex)
End If
End Sub
ScrollIntoViewsメソッドで対象の行へスクロールするのだけど、ここで問題が。メソッドにはItemsSourcesにあるオブジェクトを指定するのだけど、IList型にキャストしてインデックス値から導き出すとItemsSource自体はソートされていないので、スクロールした位置にあるオブジェクトを指定できないのね(元のコードはListにキャストしてるけどおなじだよね? Listってなに?)。
Dim s = DirectCast(ItemsSource, System.Collections.IList)
Dim i As Integer
If mousedelta < 0 Then
i = indexs.Max + 1
ElseIf mousedelta > 0 Then
i = indexs.Min - 1
End If
If i < 0 Then
i = 0
ElseIf i > s.Count - 1 Then
i = s.Count - 1
End If
Me.ScrollIntoView(s(i), Me.Columns(0))
ItemsSourceに指定するコレクションとキャストする型を考えればなんとかなりそう! ってことでたどり着いたのが、CollectionViewModel。よくは読んでいないのだけど、M-V-VMパターンについてのエントリを訳してみた3 原題"CollectionViewModel" から原文に行ってサンプルをダウンロードして該当クラスだけとりだして使ってみると一応動きました(ItemsSourceとキャストにはICollectionView、行数を取得するのにIList型にもキャストして使用)。
ソートしてもきちんとマウスホイールでスクロールできるのだけど、ものすごいCollectionViewModel生成のところかな? 時間がかかる。150行ぐらいなのだけど、ブラウザが固まってしまう……。ううーむ? ←今ここ。