WPFのDataGridは、ヘッダーをクリックするとその列でソートしてくれる。
(ちなみにソート後のSelectedIndexプロパティは並び変わった後のIndexなので、ItemsSourceへセットしたデータ配列のIndexには使えないので注意)
この並び変えを自分でカスタマイズしたい場合、DataGridのSortingイベントを利用する。
以下の例では、 大量にあるデータのうち先頭の数件だけをDataGridに表示しているが、ソート順に応じてDataGridのItemsSourceを作り変えている。
XAML
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication1" mc:Ignorable="d" Title="MainWindow" Height="400" Width="400"> <Grid Margin="10" HorizontalAlignment="Stretch"> <DataGrid x:Name="CtrlDataGrid" Sorting="CrtlDataGrid_Sorting"> </DataGrid> </Grid> </Window>
DataGridのSortingイベントを追加しメソッドを指定する。
ソース
public partial class MainWindow : Window { public class TestItem { public int Column1 { get; set; } public int Column2 { get; set; } public int Column3 { get; set; } public int Column4 { get; set; } }; List<TestItem> TestList = new List<TestItem>(); public MainWindow() { for (int i = 0; i < 1000; ++i) { var item = new TestItem(); item.Column1 = i; item.Column2 = i % 10; item.Column3 = i % 7; item.Column4 = i % 13; TestList.Add(item); } InitializeComponent(); CtrlDataGrid.ItemsSource = TestList.OrderBy(c => c.Column1).Take(13); } private void CrtlDataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e) { var i = CtrlDataGrid.SelectedIndex; MessageBox.Show(string.Format("{0}", i)); } private void CrtlDataGrid_Sorting(object sender, DataGridSortingEventArgs e) { e.Handled = true; var sortDir = e.Column.SortDirection; if (ListSortDirection.Ascending != sortDir) sortDir = ListSortDirection.Ascending; else sortDir = ListSortDirection.Descending; if (ListSortDirection.Ascending == sortDir) { if ("Column1" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderBy(c => c.Column1).Take(13); if ("Column2" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderBy(c => c.Column2).Take(13); if ("Column3" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderBy(c => c.Column3).Take(13); if ("Column4" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderBy(c => c.Column4).Take(13); } else { if ("Column1" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderByDescending(c => c.Column1).Take(13); if ("Column2" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderByDescending(c => c.Column2).Take(13); if ("Column3" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderByDescending(c => c.Column3).Take(13); if ("Column4" == e.Column.SortMemberPath) CtrlDataGrid.ItemsSource = TestList.OrderByDescending(c => c.Column4).Take(13); } foreach (var column in CtrlDataGrid.Columns) { if (column.SortMemberPath == e.Column.SortMemberPath) { column.SortDirection = sortDir; } } } }
既存のソート処理をしない (37行目)
DataGridSortingEventArgsのHandlerにtrueをセットする事で既存のソート処理が行われなくなる
新たなソート順を決める (41~44行目)
DataGridSortingEventArgsのColumn.SortDirectionに現在のソート順が入っている
null ・・・ ソートされていない
Ascending ・・・ 昇順(ヘッダーに▲が表示されている状態)
Descending ・・・ 降順(ヘッダーに▼が表示されている状態)
現在のソート順を元に新たなソート順を決めている
データを作り直す (46~67行目)
DataGridSortingEventArgsのColumn.SortMemberPathにソート対象のメンバーが入っているのでそれに従ってItemsSourceを作り直している
ヘッダーのソート順を正しくセットする (69~75行目)
通常はDataGridSortingEventArgsのColumn.SortDirectionへ新たな値をセットすれば良さそうだがItemsSourceを作り直している為かそれではうまくいかない
DataGridのColumnsから該当のカラムを見つけて新たなSortDirectionをセットする
コメントをお書きください