ListViewのヘッダークリックでソートするコードを確認しました。
再利用する場合、コードビハインドだと中身を理解するのが大変なので、ListViewSortBehaviorを作ることで再利用しやすくしてみました。
ソースコード
ファイル名:FileInfoModel.cs
public class FileInfoModel
{
public string Name { get; set; } = "";
public int Length { get; set; } = 0;
}
ファイル名:ListViewSortBehavior.cs
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.Xaml.Behaviors;
namespace ListViewSort02;
public class ListViewSortBehavior : Behavior<ListView>
{
private ListSortDirection _sortDirection;
private string _sortPropertyName = "";
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(HeaderClicked));
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(HeaderClicked));
}
private void HeaderClicked(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is GridViewColumnHeader header && header.Column != null )
{
string? propertyName = header.Column.GetValue(SortPropertyNameProperty) as string;
if (propertyName is null || string.IsNullOrEmpty(propertyName))
{
return;
}
if (_sortPropertyName == propertyName)
{
_sortDirection = _sortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
}
else
{
_sortPropertyName = propertyName;
_sortDirection = ListSortDirection.Ascending;
}
Sort(propertyName, _sortDirection);
}
}
private void Sort(string propertyName, ListSortDirection direction)
{
var files = AssociatedObject.ItemsSource;
var collectionView = CollectionViewSource.GetDefaultView(files);
collectionView.SortDescriptions.Clear();
collectionView.SortDescriptions.Add(new SortDescription(propertyName, direction));
}
public static readonly DependencyProperty SortPropertyNameProperty =
DependencyProperty.RegisterAttached("SortPropertyName", typeof(string), typeof(ListViewSortBehavior));
public static string GetSortPropertyName(DependencyObject obj)
{
return (string)obj.GetValue(SortPropertyNameProperty);
}
public static void SetSortPropertyName(DependencyObject obj, string value)
{
obj.SetValue(SortPropertyNameProperty, value);
}
}
ファイル名:MainWindow.xaml
<Window
x:Class="ListViewSort02.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:ListViewSort02"
mc:Ignorable="d"
Title="ListViewSort02"
Height="450" Width="800"
xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ListView ItemsSource="{Binding Files}">
<i:Interaction.Behaviors>
<local:ListViewSortBehavior />
</i:Interaction.Behaviors>
<ListView.View>
<GridView>
<GridViewColumn Width="200"
local:ListViewSortBehavior.SortPropertyName="Name">
<GridViewColumnHeader
x:Name="HeadName1"
Content="名前" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Width="100"
TextAlignment="Left"
Text="{Binding Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="200"
local:ListViewSortBehavior.SortPropertyName="Length">
<GridViewColumnHeader
x:Name="HeadLength1"
Content="長さ" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Width="100"
TextAlignment="Right"
Text="{Binding Length}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
ファイル名:MainWindowViewModel.cs
using System.ComponentModel;
using Reactive.Bindings;
namespace ListViewSort02;
public class MainWindowViewModel : INotifyPropertyChanged
{
// INotifyPropertyChanged
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string name) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
/**************************************************************************
* プロパティ
**************************************************************************/
// ファイルの一覧
public ReactiveCollection<FileInfoModel> Files { get; private set; } = [];
public MainWindowViewModel()
{
PropertyChanged += (s, e) => {};
Files.AddOnScheduler(new FileInfoModel(){Name = "a.txt", Length = 99});
Files.AddOnScheduler(new FileInfoModel(){Name = "b.txt", Length = 88});
Files.AddOnScheduler(new FileInfoModel(){Name = "c.txt", Length = 77});
}
}
実行
説明
前回のコードビハインドで書いたSortのコードが、View内で完結しているのでBehaviorに切り出せるのではないかと思い試してみました。
合わせてViewModelを書いてMVVMパターンにしてみました。
コメント