本記事では、メンバ変数名でリストをソートする方法を書きます。
この方法は、WPFアプリケーションのDataGridをソートするときなどに役立ちます。
- Windows10
- Microsoft Visual Studio Community2022
- .NET 6
- WPF アプリ
リストをソートする方法
通常のソート
例えば、↓のリストがあるとき
private List<FriutsViewModel> FriutListViewModel = new List<FriutsViewModel>()
{
new FriutsViewModel("りんご", "赤", 148),
new FriutsViewModel("みかん", "オレンジ", 130),
new FriutsViewModel("キウイ", "緑", 136),
new FriutsViewModel("ぶどう", "赤", 540),
new FriutsViewModel("かき", "オレンジ", 120),
new FriutsViewModel("ばなな", "黄", 108),
};
internal class FriutsViewModel
{
public string name { get; }
public string color { get; }
public int price { get; }
public FriutsViewModel(string name, string color, int price)
{
this.name = name;
this.color = color;
this.price = price;
}
}
通常ソートする場合は、
- IEnumable.OrderBy ( 昇順にソート )
- IEnumable.OrderByDescending ( 降順にソート )
を使用します。使用方法としては、
// 価格(price) で昇順( 小さい→大きい ) にソート
FriutListViewModel = FriutListViewModel.OrderBy(viewModel => viewModel.price).ToList();
// 色(color) で降順( 大きい→小さい ) にソート
FriutListViewModel = FriutListViewModel.OrderByDescending(viewModel => viewModel.color).ToList();
となります。このコードでソートが実行できます。
メンバ変数名でソート
次は、メンバ変数名でソートします。ソートするメソッドは同じです。メンバ変数名とクラスの型を引数としてソートできます。
以下メソッドを使用します。
- Type.GetProperty ( Type型の指定のプロパティを取得)
- PropertyInfo.GetValue ( プロパティ型の指定オブジェクトの値を取得 )
先ほどのコードは↓のように書き換えられます。
// 価格(price) で昇順( 小さい→大きい ) にソート
FriutListViewModel = FriutListViewModel.OrderBy(viewModel =>
{
return typeof(FriutsViewModel).GetProperty("price")?.GetValue(viewModel);
}).ToList();
// 色(color) で降順( 大きい→小さい ) にソート
FriutListViewModel = FriutListViewModel.OrderByDescending(viewModel =>
{
return typeof(FriutsViewModel).GetProperty("color")?.GetValue(viewModel);
}).ToList();
先ほどと同じ結果となります。
DataGrid のソート
メンバ変数名のソートはDataGrid のソートで役立ちます。
↓はDataGridのソートをオリジナルで実装したときの記事です。
![](https://home-programming.com/wp/wp-content/uploads/2023/01/DataGrid_SortOriginal_icatch-300x169.png)
DataGrid のヘッダーをクリックしたとき、取得できるのはリストのメンバ変数名です。
![](https://home-programming.com/wp/wp-content/uploads/2023/01/exp_zu2-1024x494.png)
色をクリックした場合、メンバ変数名”color” を取得できます。このメンバ変数名を使ってソートする必要があります。
メンバ変数名だけでは、↓のように、ネット上でよく見かけるOrderByの方法ではソートできません。
FriutListViewModel = FriutListViewModel.OrderBy(viewModel => viewModel.color).ToList();
Xamlファイル
xaml ファイルです。それぞれの列に対して、DataGridTextColumnタグのBinding属性で名称を設定しています。ヘッダークリックしたとき、この名称を文字列で取得できます。
設定する名称は、紐づくリストのメンバ変数名と一致させなければなりません。
MainWindow.xaml
<Window x:Class="DataGridProject.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:DataGridProject"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="500">
<Grid x:Name="Grid_FruitsList">
<Grid.Resources>
<FrameworkElement x:Key="proxyElement" />
</Grid.Resources>
<ContentControl Visibility="Collapsed" Content="{StaticResource proxyElement}" />
<DataGrid Margin="28,29,250,30"
AutoGenerateColumns = "False"
IsReadOnly="True"
SelectionMode="Single"
RowHeaderWidth="0"
ItemsSource="{Binding Path=_friutsModelList}"
Sorting="DataGrid_Sorting" >
<!-- 選択時に_isSelectedの値変更 -->
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="IsSelected" Value="{Binding _isSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Width="100" Binding="{Binding _name}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Content" Value="{Binding Path=DataContext._nameHeader, Source={StaticResource proxyElement}}"/>
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Width="50" Binding="{Binding _color}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Content" Value="{Binding Path=DataContext._colorHeader, Source={StaticResource proxyElement}}"/>
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Width="50" Binding="{Binding _price}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Content" Value="{Binding Path=DataContext._priceHeader, Source={StaticResource proxyElement}}"/>
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<GroupBox Margin="273,33,30,55" Header="選択中"/>
<TextBlock HorizontalAlignment="Left" Margin="280,56,0,0" TextWrapping="Wrap" Text="名前 : " VerticalAlignment="Top" RenderTransformOrigin="0,-0.937"/>
<TextBox x:Name="TextBox_Name" HorizontalAlignment="Left" Margin="325,56,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
<TextBlock HorizontalAlignment="Left" Margin="280,89,0,0" TextWrapping="Wrap" Text="色 : " VerticalAlignment="Top" RenderTransformOrigin="0.603,2.195"/>
<TextBox x:Name="TextBox_Color" HorizontalAlignment="Left" Margin="325,89,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
<TextBlock HorizontalAlignment="Left" Margin="280,124,0,0" TextWrapping="Wrap" Text="価格 : " VerticalAlignment="Top"/>
<TextBox x:Name="TextBox_Price" HorizontalAlignment="Left" Margin="325,122,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
</Grid>
</Window>
DataGridクリックで呼ばれるイベントハンドラ
クリックしたヘッダー列に対し、その位置に対応するBinding 属性で設定した名称を引数として取得できます。
MainWindow.xaml.cs ヘッダークリックで呼ばれるメソッド
/// <summary>
/// ヘッダーがクリックされたとき呼び出し
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
e.Handled = true;
string sortMemberPath = e.Column.SortMemberPath;
dataGridSortDirector.Sort(sortMemberPath);
}
DataGridSortingEventArgs のcolum.SortMemberPathが、先ほどBinding属性に設定した名称の文字列となっています。
DataGridのDataGrid.Columns のColumn要素に紐づくクラス
クラスのメンバ変数名と、Binding属性に設定した名称は同じにしています。
FriutsDataGridColumnModel.cs
namespace DataGridProject.FriutListDataGrid
{
/// <summary>
/// フルーツデータグリッド列モデル
/// </summary>
/// <remarks>MainWindow.xaml→DataGrid.Columns のColumn要素と対応</remarks>
public class FriutsDataGridColumnModel
{
/// <summary>
/// 選択状態
/// </summary>
public bool _isSelected { get; set; }
/// <summary>
/// 名称
/// </summary>
public string _name { get; set; }
/// <summary>
/// 色
/// </summary>
public string _color { get; set; }
/// <summary>
/// 価格
/// </summary>
public int _price { get; set; }
}
}
DataGridと紐づくクラス
メンバ変数名に対するソートはここで行っています。Binding属性で名称を引数にして、ソートを行っています。
FriutsListGridModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace DataGridProject.FriutListDataGrid
{
/// <summary>
/// フルーツリストグリッドモデル
/// </summary>
/// <remarks>MainWindow.xaml→Grid_FruitsList と対応</remarks>
public class FriutsListGridModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// 名称ヘッダー
/// </summary>
public string _nameHeader { get; set; }
/// <summary>
/// 色ヘッダー
/// </summary>
public string _colorHeader { get; set; }
/// <summary>
/// 価格ヘッダー
/// </summary>
public string _priceHeader { get; set; }
/// <summary>
/// フルーツデータグリッド列モデル一覧
/// </summary>
public ObservableCollection<FriutsDataGridColumnModel> _friutsModelList { get; set; }
/// <summary>
/// 降順にソートする
/// </summary>
/// <param name="sortMemberPath">ソートメンバーパス</param>
public void SortByDescending( string sortMemberPath)
{
_friutsModelList = new ObservableCollection<FriutsDataGridColumnModel>(
_friutsModelList.OrderByDescending(c => typeof(FriutsDataGridColumnModel).GetProperty(sortMemberPath)?.GetValue(c))
);
NotifyPropertyChanged(nameof(FriutsListGridModel._friutsModelList));
}
/// <summary>
/// 昇順にソートする
/// </summary>
/// <param name="sortMemberPath">ソートメンバーパス</param>
public void SortByAscending(string sortMemberPath)
{
_friutsModelList = new ObservableCollection<FriutsDataGridColumnModel>(
_friutsModelList.OrderBy(c => typeof(FriutsDataGridColumnModel).GetProperty(sortMemberPath)?.GetValue(c))
);
NotifyPropertyChanged(nameof(FriutsListGridModel._friutsModelList));
}
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
プロジェクト一覧は↓から取得できます。
まとめ
メンバ変数名でリストをソートする方法を書きました。
この方法は、WPFアプリケーションのDataGridをソートするときなどに役立ちます。
コメント