WPFにはListViewのGridViewモードとDataGridの2つのコントロールで表形式の表示が行えます。DataGridの方はソート機能が組み込まれていますが、ListViewの方は自前でソートコードを記述する必要があります。MSDNにも方法 : ヘッダーがクリックされたときに GridView 列を並べ替えるという記事が用意されていたりしますがいまいちパッとしません。 そこで簡単に扱えるようにライブラリ化しました。 使い方は
<ListView ItemsSource="{Binding SelectedValue.Files, ElementName=tree}" xmlns:v="clr-namespace:Sayuri.Windows;assembly=GridViewSortLibrary" v:GridViewSort.IsEnabled="True"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </ListView.ItemContainerStyle> <ListView.View> <GridView> <GridViewColumn Header="名前" DisplayMemberBinding="{Binding Name}" /> <GridViewColumn Header="サイズ" v:GridViewSort.MemberPath="Length"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock TextAlignment="Right" Text="{Binding Length, StringFormat=N0}" /> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView>こんな感じです。要点は
- xmlnsでアセンブリ・名前空間を指定します
- <ListView>に添付プロパティGridViewSort.IsEnabled="True"を指定します
- <GridViewColumn>にDisplayMemberBindingの指定があればそのプロパティでソートが行われます
- <GridViewColumn>にDisplayMemberBindingを指定できない場合はGridViewSort.MemberPathにプロパティ名をしてします
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sayuri.Windows | |
open System | |
open System.ComponentModel | |
open System.Windows | |
open System.Windows.Controls | |
open System.Windows.Data | |
open System.Windows.Documents | |
open System.Windows.Media | |
type GridViewSort () = | |
static let ascending = Geometry.Parse "M 0 4 L 3.5 0 L 7 4 Z" | |
static let descending = Geometry.Parse "M 0 0 L 3.5 4 L 7 0 Z" | |
static let applySort (listView : ListView) (columnHeader : GridViewColumnHeader) propertyName = | |
let adorner : Adorner = GridViewSort.GetSortIcon listView | |
if adorner <> null then | |
(AdornerLayer.GetAdornerLayer adorner.AdornedElement).Remove adorner | |
let items = listView.Items | |
let direction, geometry, insert = | |
if items.SortDescriptions.Count = 0 then ListSortDirection.Ascending, ascending, true | |
elif (let current = items.SortDescriptions.[0] in | |
current.PropertyName <> propertyName || current.Direction = ListSortDirection.Descending) then ListSortDirection.Ascending, ascending, false | |
else ListSortDirection.Descending, descending, false | |
if String.IsNullOrEmpty propertyName then | |
GridViewSort.SetSortIcon(listView, null) | |
else | |
let sortIcon = { new Adorner(columnHeader) with | |
override __.OnRender (drawingContext) = | |
base.OnRender drawingContext | |
if columnHeader.RenderSize.Width < 20.0 then () else | |
drawingContext.PushTransform <| TranslateTransform(columnHeader.RenderSize.Width - 15.0, (columnHeader.RenderSize.Height - 5.0) / 2.0) | |
drawingContext.DrawGeometry(Brushes.Black, null, geometry) | |
drawingContext.Pop() } | |
(AdornerLayer.GetAdornerLayer columnHeader).Add sortIcon | |
GridViewSort.SetSortIcon(listView, sortIcon) | |
let description = SortDescription(propertyName, direction) | |
if insert then items.SortDescriptions.Add description | |
else items.SortDescriptions.[0] <- description | |
static let columnHeaderClick = RoutedEventHandler(fun _ e -> | |
let clickedHeader = e.OriginalSource :?> GridViewColumnHeader | |
let clickedColumn = clickedHeader.Column | |
if clickedColumn = null then () else | |
let propertyName = GridViewSort.GetMemberPath clickedColumn | |
let propertyName = if String.IsNullOrEmpty propertyName |> not then propertyName else | |
match clickedColumn.DisplayMemberBinding with | |
| :? Binding as binding when binding.Path <> null -> binding.Path.Path | |
| _ -> null | |
if String.IsNullOrEmpty propertyName |> not then | |
let rec loop reference = | |
match VisualTreeHelper.GetParent reference with | |
| :? ListView as listView -> Some listView | |
| null -> None | |
| parent -> loop parent | |
loop clickedHeader |> Option.iter (fun listView -> applySort listView clickedHeader propertyName)) | |
static member val SortIconProperty = DependencyProperty.RegisterAttached("SortIcon", typeof<Adorner>, typeof<GridViewSort>) | |
static member private GetSortIcon (target : ListView) = | |
target.GetValue GridViewSort.SortIconProperty :?> Adorner | |
static member SetSortIcon (target : ListView, value : Adorner) = | |
target.SetValue(GridViewSort.SortIconProperty, value) | |
static member val MemberPathProperty = DependencyProperty.RegisterAttached("MemberPath", typeof<string>, typeof<GridViewSort>) | |
static member GetMemberPath (target : GridViewColumn) = | |
target.GetValue GridViewSort.MemberPathProperty :?> string | |
static member SetMemberPath (target : GridViewColumn, value : string) = | |
target.SetValue(GridViewSort.MemberPathProperty, value) | |
static member val IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", typeof<bool>, typeof<GridViewSort>, UIPropertyMetadata(false, fun o e -> | |
let listView = o :?> ListView | |
match downcast e.OldValue, downcast e.NewValue with | |
| true, false -> listView.RemoveHandler(GridViewColumnHeader.ClickEvent, columnHeaderClick) | |
| false, true -> listView.AddHandler(GridViewColumnHeader.ClickEvent, columnHeaderClick) | |
| _, _ -> ())) | |
static member GetIsEnabled (target : ListView) = | |
target.GetValue GridViewSort.IsEnabledProperty :?> bool | |
static member SetIsEnabled (target : ListView, value : bool) = | |
target.SetValue(GridViewSort.IsEnabledProperty, value) |
作成にあたって次の2つの記事を参考にしました。
0 件のコメント:
コメントを投稿