C#のWPFでDataGridのソートをカスタマイズ

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をセットする