トップ回答者
WPF Listviewの列並び替えアルゴリズムのユーザー定義

質問
-
WPF でListviewを動的にコントロールするプログラムをVisual Basicで書いています。
Listviewの内容を、ヘッダーをクリックして正順、逆順でソートするところまでは行きましたが、ソートのアルゴリズムが文字列の処理を対象に設計されているので、
同じ列に表示された1.2.3.9.11 という整数を正順にソートしたいところが1.11.2.3.9と並び替えられてしまいます。
プログラムは、下記のリンクにあるものを使用しています。
方法 : ヘッダーがクリックされたときに GridView 列を並べ替える
http://msdn.microsoft.com/ja-jp/library/ms745786.aspx従来のWindows FormではIcompareableインターフェイスをオーバーライドして、ユーザー定義のソートアルゴリズムを作成できたのですが、WPFになってからはどうやってソートアルゴリズムをカスタマイズしたら良いのでしょうか教えて下さい。なお、XAMLでは「Listviewを動的にコントロールする」という動作が実現できませんから、ソースにXAMLを使うのはやめて下さい。
また、MSDN WEBサイトのどこを見ればこの問題の解決方法が記載されているのでしょうか。
私は初心者で、VB以外の言語は読めませんので、分かり易く回答して下さい。
回答
-
データソースが IList(かつ IBindingList でない)の場合の既定の ICollectionView 実装である ListCollectionView には、IComparer 型の CustomSort プロパティが存在します。これを使えるなら、ICollectionView を ListCollectionView に CType して設定するだけです。
データソースのビューが ListCollectionView じゃない場合はまた違う方法になるでしょう。
また、MSDN WEBサイトのどこを見ればこの問題の解決方法が記載されているのでしょうか。
サンプルを見れば、ヘッダクリック時のイベントハンドラは基本的にソート対象を抽出しているだけで、実際にソートしているのは Sort メソッドであること、Sort メソッドにおいてソート処理の主体は ICollectionView であることは分かると思います。
そこから、ICollectionView → データバインディングの概要 → データバインディングに関する「方法」トピック → ビュー内のデータを並べ替える → CustomSort 、といった流れになりますかね。
VB以外の言語は読めませんので、
WPF を扱うのであれば、C# を避けることはできないと言っていいと思います。MSDN はまだしも、ほとんどの Web 上の情報は C# で書かれていると感じるからです。
知りたいことの大部分は「ライブラリの使い方」のはずです。そうであれば、VB だろうが C# だろうが、クラス名やメソッド名さえ分かればどういうことをすればいいのか大体見当はつきます。いちいちコードを一行ずつ追う必要はあまりありません。
ロジック的な疑問に関してはそういうわけにもいきませんが、基礎的な文法に関しては VB と少し記法が違うだけ程度の差ですので、ネットに転がっている C# → VB converter を使うなどすれば大抵は解決します。
- 回答としてマーク 馋涎欲滴 2011年11月21日 14:18
すべての返信
-
データソースが IList(かつ IBindingList でない)の場合の既定の ICollectionView 実装である ListCollectionView には、IComparer 型の CustomSort プロパティが存在します。これを使えるなら、ICollectionView を ListCollectionView に CType して設定するだけです。
データソースのビューが ListCollectionView じゃない場合はまた違う方法になるでしょう。
また、MSDN WEBサイトのどこを見ればこの問題の解決方法が記載されているのでしょうか。
サンプルを見れば、ヘッダクリック時のイベントハンドラは基本的にソート対象を抽出しているだけで、実際にソートしているのは Sort メソッドであること、Sort メソッドにおいてソート処理の主体は ICollectionView であることは分かると思います。
そこから、ICollectionView → データバインディングの概要 → データバインディングに関する「方法」トピック → ビュー内のデータを並べ替える → CustomSort 、といった流れになりますかね。
VB以外の言語は読めませんので、
WPF を扱うのであれば、C# を避けることはできないと言っていいと思います。MSDN はまだしも、ほとんどの Web 上の情報は C# で書かれていると感じるからです。
知りたいことの大部分は「ライブラリの使い方」のはずです。そうであれば、VB だろうが C# だろうが、クラス名やメソッド名さえ分かればどういうことをすればいいのか大体見当はつきます。いちいちコードを一行ずつ追う必要はあまりありません。
ロジック的な疑問に関してはそういうわけにもいきませんが、基礎的な文法に関しては VB と少し記法が違うだけ程度の差ですので、ネットに転がっている C# → VB converter を使うなどすれば大抵は解決します。
- 回答としてマーク 馋涎欲滴 2011年11月21日 14:18
-
御回答ありがとうございます。教示いただいた回答を元に、MSDNドキュメントの一文字一句を理解しながら読み進めていますが解決できません。
「サンプルを見れば、ヘッダクリック時のイベントハンドラは基本的にソート対象を抽出しているだけで、実際にソートしているのは Sort メソッドであること、Sort メソッドにおいてソート処理の主体は ICollectionView であることは分かると思います。 そこから、ICollectionView→データバインディングの概要→データバインディングに関する「方法」トピック →ビュー内のデータを並べ替える → CustomSort 、といった流れになりますかね。」とありますが、ICollectionView インターフェイスで公開されるメンバー、及びSortDescriptionsプロパティーのドキュメントにも、sort()メソッドについての記述がありません。「実際にソートしているのは Sort メソッドであること」 ←この部分の引用元が分からないです。
listviewは、表示ソースとなるコレクションクラスをディスプレーするための容器として考え、ソートはコレクションクラスに対して行った後にlistviewの表示をリフレッシュするという作戦に変更しようかと考えています。こうすれば、コレクションクラスにはarray()の様な初歩的なクラスが利用でき、思いのままにカスタムソートができるからです。皆さん、どう思われますでしょうか。 -
「実際にソートしているのは Sort メソッドであること」 ←この部分の引用元が分からないです。
最初にリンクしていた このページ の下の方に書かれていませんか?
見つからないのであれば、「Private Sub Sort」で検索してみてください。このサンプルでは Window1 に独自の Sort メソッドを作っており、GridViewColumnHeaderClickedHandler メソッドから呼び出しています。
肝心なのはこの Sort メソッド内で使っている ICollectionView に対する操作なので、「Sort メソッド」を探すことではありません。# 具体的方法は知りませんが、ページの読み方に関してだったのでレスをつけました。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 編集済み AzuleanMVP, Moderator 2011年11月19日 13:09
-
ListCollectionView.CustomSortのサンプルソースが海外のサイトにありましたので、参考にして完成させました。
WPFについてはまだ全然知識がありませんが、着実に経験を積んでいきたいと思います。回答されたお二方には大変感謝します。
*XAML*
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Height="305" Name="StackPanel1" Width="439" >
<!--<ListView Height="98" Name="ListView1" Width="269" VerticalAlignment="Top" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler" />-->
<ListView Height="98" Name="ListView1" Width="269" VerticalAlignment="Top" />
<Button Content="Button" Height="37" Name="Button1" Width="60" VerticalAlignment="Top" />
</StackPanel>
</Window>*VB*
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Class MainWindow
Dim S_direction As Integer = 1
Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim lv1 As ListView = Me.ListView1
Dim gvc As GridViewColumn
Dim myGridView As New GridView()
gvc = New GridViewColumn()
gvc.Header = "Num"
gvc.Width = 100
myGridView.Columns.Add(gvc)
myGridView.Columns(0).DisplayMemberBinding = New Binding("Num")
lv1.View = myGridView
lv1.Items.Clear()
lv1.ItemsSource = New LVsource
End Sub
' Itemsource class
Public Class LVsource
Inherits ObservableCollection(Of Str0)
Public Sub New()
Add(New Str0("1"))
Add(New Str0("11"))
Add(New Str0("9"))
Add(New Str0("3"))
End Sub
End Class
'custom structure
Public Structure Str0
Public _num As String
Public Sub New(ByRef s1 As String)
Me._num = s1
End Sub
Public Property Num() As String
Get
Return _num
End Get
Set(ByVal value As String)
_num = value
End Set
End Property
End Structure
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim dataView As ListCollectionView = CType(CollectionViewSource.GetDefaultView(Me.ListView1.ItemsSource), ListCollectionView)
dataView.CustomSort = New SortByNum(S_direction)
S_direction = -S_direction
End Sub
Public Class SortByNum
Implements IComparer
Dim sd As Integer
Sub New(i As Integer)
sd = i
End Sub
Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare
If Integer.Parse(CType(x, Str0).Num) > Integer.Parse(CType(y, Str0).Num) Then
Return (-sd)
Else
Return (sd)
End If
End Function
End Class
End Class