在列标题单击时使 WPF ListView/GridView 排序的最佳方法?
Posted
技术标签:
【中文标题】在列标题单击时使 WPF ListView/GridView 排序的最佳方法?【英文标题】:Best way to make WPF ListView/GridView sort on column-header clicking? 【发布时间】:2010-11-02 21:49:23 【问题描述】:互联网上有 很多 解决方案试图填补 WPF 中这个看似非常基本的遗漏。我真的很困惑什么是“最好的”方式。例如...我希望列标题中有小向上/向下箭头来指示排序方向。显然有 3 种不同的方法可以做到这一点,一些使用代码,一些使用标记,一些使用标记加代码,所有这些看起来都像是一种 hack。
以前有没有人遇到过这个问题,并找到了他们完全满意的解决方案? WPF 中缺少这样一个基本的 WinForms 功能并需要被入侵,这似乎很奇怪。
【问题讨论】:
回答上面关于如何让 util 被识别的问题。将 xmlns:util="clr-namespace:Wpf.Util" 添加到 xaml 文档顶部的命名空间 如果可能的话.. 使用 DataGrid。 【参考方案1】:我写了一组附加属性来自动排序GridView
,你可以查看here。它不处理向上/向下箭头,但可以轻松添加。
<ListView ItemsSource="Binding Persons"
IsSynchronizedWithCurrentItem="True"
util:GridViewSort.AutoSort="True">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name"
DisplayMemberBinding="Binding Name"
util:GridViewSort.PropertyName="Name"/>
<GridViewColumn Header="First name"
DisplayMemberBinding="Binding FirstName"
util:GridViewSort.PropertyName="FirstName"/>
<GridViewColumn Header="Date of birth"
DisplayMemberBinding="Binding DateOfBirth"
util:GridViewSort.PropertyName="DateOfBirth"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
【讨论】:
谢谢 Thomas,您对排序问题的解决方案优雅、易于使用且非常灵活。换句话说:完美!给其他人的提示:1) 使用 Thomas 文章中链接到的更新版本,以及 2) 在 cmets 中使用更漂亮的 Alex 字形版本。 我是 WPF 新手,不太了解这个“util”位。那是指什么?编辑:nm ...有一个名为“查看源代码”的小链接并没有立即跳出来。这扩展了类的源代码 我非常喜欢!我正在动态添加/删除项目,这在不改变顺序的情况下效果很好。但是如何设置排序的初始状态?CollectionViewSource.GetDefaultView(MyList.ItemsSource).SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));
不起作用。
@zee,它应该可以工作,但它不会显示排序字形...我还没有实现设置初始顺序的方法,但你总是可以尝试修改我的代码; )
我的错 - 它运行良好! (我实例化了一个新列表而不是清除,所以 SortDescriptions 被重置)对不起【参考方案2】:
MSDN has an easy way to perform sorting on columns 带有上/下字形。不过,这个例子并不完整——他们没有解释如何为字形使用数据模板。下面是我要使用我的 ListView 的内容。这适用于 .Net 4。
在您的 ListView 中,您必须指定一个事件处理程序以触发对 GridViewColumnHeader 的单击。我的 ListView 如下所示:
<ListView Name="results" GridViewColumnHeader.Click="results_Click">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="Binding Path=ContactName">
<GridViewColumn.Header>
<GridViewColumnHeader Content="Contact Name" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="ContactName" />
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="Binding Path=PrimaryPhone">
<GridViewColumn.Header>
<GridViewColumnHeader Content="Contact Number" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="PrimaryPhone"/>
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
在你的代码后面,设置代码来处理排序:
// Global objects
BindingListCollectionView blcv;
GridViewColumnHeader _lastHeaderClicked = null;
ListSortDirection _lastDirection = ListSortDirection.Ascending;
// Header click event
void results_Click(object sender, RoutedEventArgs e)
GridViewColumnHeader headerClicked =
e.OriginalSource as GridViewColumnHeader;
ListSortDirection direction;
if (headerClicked != null)
if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
if (headerClicked != _lastHeaderClicked)
direction = ListSortDirection.Ascending;
else
if (_lastDirection == ListSortDirection.Ascending)
direction = ListSortDirection.Descending;
else
direction = ListSortDirection.Ascending;
string header = headerClicked.Column.Header as string;
Sort(header, direction);
if (direction == ListSortDirection.Ascending)
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowUp"] as DataTemplate;
else
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowDown"] as DataTemplate;
// Remove arrow from previously sorted header
if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked)
_lastHeaderClicked.Column.HeaderTemplate = null;
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
// Sort code
private void Sort(string sortBy, ListSortDirection direction)
blcv.SortDescriptions.Clear();
SortDescription sd = new SortDescription(sortBy, direction);
blcv.SortDescriptions.Add(sd);
blcv.Refresh();
然后在您的 XAML 中,您需要添加您在排序方法中指定的两个 DataTemplate:
<DataTemplate x:Key="HeaderTemplateArrowUp">
<DockPanel LastChildFill="True" Width="Binding ActualWidth, RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type GridViewColumnHeader">
<Path x:Name="arrowUp" StrokeThickness="1" Fill="Gray" Data="M 5,10 L 15,10 L 10,5 L 5,10" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/>
<TextBlock Text="Binding " />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="HeaderTemplateArrowDown">
<DockPanel LastChildFill="True" Width="Binding ActualWidth, RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type GridViewColumnHeader">
<Path x:Name="arrowDown" StrokeThickness="1" Fill="Gray" Data="M 5,5 L 10,10 L 15,5 L 5,5" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/>
<TextBlock Text="Binding " />
</DockPanel>
</DataTemplate>
使用 DockPanel
并将 LastChildFill
设置为 true 将使字形保持在标题右侧,并让标签填充其余空间。我将DockPanel
宽度绑定到GridViewColumnHeader
的ActualWidth
,因为我的列没有宽度,这可以让它们自动适应内容。不过,我确实在列上设置了MinWidth
s,这样字形就不会掩盖列标题。 TextBlock Text
设置为空绑定,显示标题中指定的列名。
【讨论】:
这没有指定 XAML 中放置 DataTemplates Grid.Resources 的位置? @Mark 这可能帮不了你了,但是模板应该放在根元素的资源中,通常是<Window.Resources>
或<UserControl.Resources>
。高温高压 ;)
@CptRobby 嗨.. 对我来说,由于 blcv 没有初始化,它给出了一个空引用异常......那么这段代码如何适用于任何人?
@JayNirgudkar 我不是这个的作者,Jared Harley 是。但我可以告诉你,blcv 是他用作 ListView 的 ItemsSource 的东西。你不必做同样的事情。单击他提供的 MSDN 链接以获取处理 ItemsSource 的另一种方法。
MSDN 示例假定headerClicked.Column.Header
(即标题文本)等价于(headerClicked.Column.DisplayMemberBinding as Binding).Path.Path
(即绑定路径)。对标题文本进行排序不起作用。很奇怪。【参考方案3】:
这完全取决于,如果您使用 WPF 工具包中的 DataGrid,那么有一个内置排序,甚至是非常有用的多列排序。在这里查看更多:
Vincent Sibals Blog
或者,如果您使用不支持排序的其他控件,我建议您使用以下方法:
Li Gao's Custom Sorting
接着是:
Li Gao's Faster Sorting
【讨论】:
【参考方案4】:我使用 MVVM,所以我创建了一些我自己的附加属性,使用 Thomas 的作为参考。当您单击标题时,它会一次对一列进行排序,在升序和降序之间切换。它使用第一列从一开始就排序。它显示了 Win7/8 风格的字形。
通常,您只需将 main 属性设置为 true(但您必须显式声明 GridViewColumnHeaders):
<Window xmlns:local="clr-namespace:MyProjectNamespace">
<Grid>
<ListView local:App.EnableGridViewSort="True" ItemsSource="Binding LVItems">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="Binding Property1">
<GridViewColumnHeader Content="Prop 1" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="Binding Property2">
<GridViewColumnHeader Content="Prop 2" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
<Window>
如果您想对与显示不同的属性进行排序,则必须声明:
<GridViewColumn DisplayMemberBinding="Binding Property3"
local:App.GridViewSortPropertyName="Property4">
<GridViewColumnHeader Content="Prop 3" />
</GridViewColumn>
这是附加属性的代码,我喜欢偷懒,把它们放在提供的App.xaml.cs中:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data.
using System.Windows.Media;
using System.Windows.Media.Media3D;
namespace MyProjectNamespace
public partial class App : Application
#region GridViewSort
public static DependencyProperty GridViewSortPropertyNameProperty =
DependencyProperty.RegisterAttached(
"GridViewSortPropertyName",
typeof(string),
typeof(App),
new UIPropertyMetadata(null)
);
public static string GetGridViewSortPropertyName(GridViewColumn gvc)
return (string)gvc.GetValue(GridViewSortPropertyNameProperty);
public static void SetGridViewSortPropertyName(GridViewColumn gvc, string n)
gvc.SetValue(GridViewSortPropertyNameProperty, n);
public static DependencyProperty CurrentSortColumnProperty =
DependencyProperty.RegisterAttached(
"CurrentSortColumn",
typeof(GridViewColumn),
typeof(App),
new UIPropertyMetadata(
null,
new PropertyChangedCallback(CurrentSortColumnChanged)
)
);
public static GridViewColumn GetCurrentSortColumn(GridView gv)
return (GridViewColumn)gv.GetValue(CurrentSortColumnProperty);
public static void SetCurrentSortColumn(GridView gv, GridViewColumn value)
gv.SetValue(CurrentSortColumnProperty, value);
public static void CurrentSortColumnChanged(
object sender, DependencyPropertyChangedEventArgs e)
GridViewColumn gvcOld = e.OldValue as GridViewColumn;
if (gvcOld != null)
CurrentSortColumnSetGlyph(gvcOld, null);
public static void CurrentSortColumnSetGlyph(GridViewColumn gvc, ListView lv)
ListSortDirection lsd;
Brush brush;
if (lv == null)
lsd = ListSortDirection.Ascending;
brush = Brushes.Transparent;
else
SortDescriptionCollection sdc = lv.Items.SortDescriptions;
if (sdc == null || sdc.Count < 1) return;
lsd = sdc[0].Direction;
brush = Brushes.Gray;
FrameworkElementFactory fefGlyph =
new FrameworkElementFactory(typeof(Path));
fefGlyph.Name = "arrow";
fefGlyph.SetValue(Path.StrokeThicknessProperty, 1.0);
fefGlyph.SetValue(Path.FillProperty, brush);
fefGlyph.SetValue(StackPanel.HorizontalAlignmentProperty,
HorizontalAlignment.Center);
int s = 4;
if (lsd == ListSortDirection.Ascending)
PathFigure pf = new PathFigure();
pf.IsClosed = true;
pf.StartPoint = new Point(0, s);
pf.Segments.Add(new LineSegment(new Point(s * 2, s), false));
pf.Segments.Add(new LineSegment(new Point(s, 0), false));
PathGeometry pg = new PathGeometry();
pg.Figures.Add(pf);
fefGlyph.SetValue(Path.DataProperty, pg);
else
PathFigure pf = new PathFigure();
pf.IsClosed = true;
pf.StartPoint = new Point(0, 0);
pf.Segments.Add(new LineSegment(new Point(s, s), false));
pf.Segments.Add(new LineSegment(new Point(s * 2, 0), false));
PathGeometry pg = new PathGeometry();
pg.Figures.Add(pf);
fefGlyph.SetValue(Path.DataProperty, pg);
FrameworkElementFactory fefTextBlock =
new FrameworkElementFactory(typeof(TextBlock));
fefTextBlock.SetValue(TextBlock.HorizontalAlignmentProperty,
HorizontalAlignment.Center);
fefTextBlock.SetValue(TextBlock.TextProperty, new Binding());
FrameworkElementFactory fefDockPanel =
new FrameworkElementFactory(typeof(StackPanel));
fefDockPanel.SetValue(StackPanel.OrientationProperty,
Orientation.Vertical);
fefDockPanel.AppendChild(fefGlyph);
fefDockPanel.AppendChild(fefTextBlock);
DataTemplate dt = new DataTemplate(typeof(GridViewColumn));
dt.VisualTree = fefDockPanel;
gvc.HeaderTemplate = dt;
public static DependencyProperty EnableGridViewSortProperty =
DependencyProperty.RegisterAttached(
"EnableGridViewSort",
typeof(bool),
typeof(App),
new UIPropertyMetadata(
false,
new PropertyChangedCallback(EnableGridViewSortChanged)
)
);
public static bool GetEnableGridViewSort(ListView lv)
return (bool)lv.GetValue(EnableGridViewSortProperty);
public static void SetEnableGridViewSort(ListView lv, bool value)
lv.SetValue(EnableGridViewSortProperty, value);
public static void EnableGridViewSortChanged(
object sender, DependencyPropertyChangedEventArgs e)
ListView lv = sender as ListView;
if (lv == null) return;
if (!(e.NewValue is bool)) return;
bool enableGridViewSort = (bool)e.NewValue;
if (enableGridViewSort)
lv.AddHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(EnableGridViewSortGVHClicked)
);
if (lv.View == null)
lv.Loaded += new RoutedEventHandler(EnableGridViewSortLVLoaded);
else
EnableGridViewSortLVInitialize(lv);
else
lv.RemoveHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(EnableGridViewSortGVHClicked)
);
public static void EnableGridViewSortLVLoaded(object sender, RoutedEventArgs e)
ListView lv = e.Source as ListView;
EnableGridViewSortLVInitialize(lv);
lv.Loaded -= new RoutedEventHandler(EnableGridViewSortLVLoaded);
public static void EnableGridViewSortLVInitialize(ListView lv)
GridView gv = lv.View as GridView;
if (gv == null) return;
bool first = true;
foreach (GridViewColumn gvc in gv.Columns)
if (first)
EnableGridViewSortApplySort(lv, gv, gvc);
first = false;
else
CurrentSortColumnSetGlyph(gvc, null);
public static void EnableGridViewSortGVHClicked(
object sender, RoutedEventArgs e)
GridViewColumnHeader gvch = e.OriginalSource as GridViewColumnHeader;
if (gvch == null) return;
GridViewColumn gvc = gvch.Column;
if(gvc == null) return;
ListView lv = VisualUpwardSearch<ListView>(gvch);
if (lv == null) return;
GridView gv = lv.View as GridView;
if (gv == null) return;
EnableGridViewSortApplySort(lv, gv, gvc);
public static void EnableGridViewSortApplySort(
ListView lv, GridView gv, GridViewColumn gvc)
bool isEnabled = GetEnableGridViewSort(lv);
if (!isEnabled) return;
string propertyName = GetGridViewSortPropertyName(gvc);
if (string.IsNullOrEmpty(propertyName))
Binding b = gvc.DisplayMemberBinding as Binding;
if (b != null && b.Path != null)
propertyName = b.Path.Path;
if (string.IsNullOrEmpty(propertyName)) return;
ApplySort(lv.Items, propertyName);
SetCurrentSortColumn(gv, gvc);
CurrentSortColumnSetGlyph(gvc, lv);
public static void ApplySort(ICollectionView view, string propertyName)
if (string.IsNullOrEmpty(propertyName)) return;
ListSortDirection lsd = ListSortDirection.Ascending;
if (view.SortDescriptions.Count > 0)
SortDescription sd = view.SortDescriptions[0];
if (sd.PropertyName.Equals(propertyName))
if (sd.Direction == ListSortDirection.Ascending)
lsd = ListSortDirection.Descending;
else
lsd = ListSortDirection.Ascending;
view.SortDescriptions.Clear();
view.SortDescriptions.Add(new SortDescription(propertyName, lsd));
#endregion
public static T VisualUpwardSearch<T>(DependencyObject source)
where T : DependencyObject
return VisualUpwardSearch(source, x => x is T) as T;
public static DependencyObject VisualUpwardSearch(
DependencyObject source, Predicate<DependencyObject> match)
DependencyObject returnVal = source;
while (returnVal != null && !match(returnVal))
DependencyObject tempReturnVal = null;
if (returnVal is Visual || returnVal is Visual3D)
tempReturnVal = VisualTreeHelper.GetParent(returnVal);
if (tempReturnVal == null)
returnVal = LogicalTreeHelper.GetParent(returnVal);
else
returnVal = tempReturnVal;
return returnVal;
【讨论】:
【参考方案5】:我对微软的方式做了一个改编,我重写了ListView
控件来创建一个SortableListView
:
public partial class SortableListView : ListView
private GridViewColumnHeader lastHeaderClicked = null;
private ListSortDirection lastDirection = ListSortDirection.Ascending;
public void GridViewColumnHeaderClicked(GridViewColumnHeader clickedHeader)
ListSortDirection direction;
if (clickedHeader != null)
if (clickedHeader.Role != GridViewColumnHeaderRole.Padding)
if (clickedHeader != lastHeaderClicked)
direction = ListSortDirection.Ascending;
else
if (lastDirection == ListSortDirection.Ascending)
direction = ListSortDirection.Descending;
else
direction = ListSortDirection.Ascending;
string sortString = ((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path;
Sort(sortString, direction);
lastHeaderClicked = clickedHeader;
lastDirection = direction;
private void Sort(string sortBy, ListSortDirection direction)
ICollectionView dataView = CollectionViewSource.GetDefaultView(this.ItemsSource != null ? this.ItemsSource : this.Items);
dataView.SortDescriptions.Clear();
SortDescription sD = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sD);
dataView.Refresh();
((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path
行位处理列名与其绑定路径不同的情况,Microsoft 方法不这样做。
我想拦截GridViewColumnHeader.Click
事件,这样我就不必再考虑它了,但我找不到办法。因此,我在 XAML 中为每个 SortableListView
添加以下内容:
GridViewColumnHeader.Click="SortableListViewColumnHeaderClicked"
然后在任何包含任意数量SortableListView
s 的Window
上,只需添加以下代码:
private void SortableListViewColumnHeaderClicked(object sender, RoutedEventArgs e)
((Controls.SortableListView)sender).GridViewColumnHeaderClicked(e.OriginalSource as GridViewColumnHeader);
其中Controls
只是您在其中创建SortableListView
控件的命名空间的XAML ID。
所以,这确实可以防止排序端的代码重复,您只需要记住按上述方式处理事件即可。
【讨论】:
我从您的解决方案中汲取灵感并走上了同样的道路,要访问 GridViewColumnHeader.Click 事件,您可以在构造函数中添加一个处理程序。 this.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(GridViewColumnHeaderClicked));【参考方案6】:如果您有一个列表视图并将其转换为一个网格视图,您可以通过这样做轻松地使您的网格视图列标题可点击。
<Style TargetType="GridViewColumnHeader">
<Setter Property="Command" Value="Binding CommandOrderBy"/>
<Setter Property="CommandParameter" Value="Binding RelativeSource=RelativeSource Self,Path=Content"/>
</Style>
然后在你的代码中设置一个委托命令。
public DelegateCommand CommandOrderBy get return new DelegateCommand(Delegated_CommandOrderBy);
private void Delegated_CommandOrderBy(object obj)
throw new NotImplementedException();
我假设你们都知道如何在这里制作 ICommand DelegateCommand。 这让我可以在 ViewModel 中单击所有视图。
我只是添加了这个,以便有多种方法可以完成同一件事。 我没有编写用于在标题中添加箭头按钮的代码,但这将以 XAML 样式完成,您需要重新设计 JanDotNet 在其代码中的整个标题。
【讨论】:
【参考方案7】:总结现有答案和 cmets 的所有工作部分的解决方案,包括列标题模板:
查看:
<ListView x:Class="MyNamspace.MyListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
ItemsSource="Binding Items"
GridViewColumnHeader.Click="ListViewColumnHeaderClick">
<ListView.Resources>
<Style TargetType="Grid" x:Key="HeaderGridStyle">
<Setter Property="Height" Value="20" />
</Style>
<Style TargetType="TextBlock" x:Key="HeaderTextBlockStyle">
<Setter Property="Margin" Value="5,0,0,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="Path" x:Key="HeaderPathStyle">
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="Fill" Value="Gray" />
<Setter Property="Width" Value="20" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5,0,5,0" />
<Setter Property="SnapsToDevicePixels" Value="True" />
</Style>
<DataTemplate x:Key="HeaderTemplateDefault">
<Grid Style="StaticResource HeaderGridStyle">
<TextBlock Text="Binding " Style="StaticResource HeaderTextBlockStyle" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="HeaderTemplateArrowUp">
<Grid Style="StaticResource HeaderGridStyle">
<Path Data="M 7,3 L 13,3 L 10,0 L 7,3" Style="StaticResource HeaderPathStyle" />
<TextBlock Text="Binding " Style="StaticResource HeaderTextBlockStyle" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="HeaderTemplateArrowDown">
<Grid Style="StaticResource HeaderGridStyle">
<Path Data="M 7,0 L 10,3 L 13,0 L 7,0" Style="StaticResource HeaderPathStyle" />
<TextBlock Text="Binding " Style="StaticResource HeaderTextBlockStyle" />
</Grid>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderTemplate="StaticResource HeaderTemplateDefault">
<GridViewColumn Header="Name" DisplayMemberBinding="Binding NameProperty" />
<GridViewColumn Header="Type" Width="45" DisplayMemberBinding="Binding TypeProperty"/>
<!-- ... -->
</GridView>
</ListView.View>
</ListView>
代码隐藏:
public partial class MyListView : ListView
GridViewColumnHeader _lastHeaderClicked = null;
public MyListView()
InitializeComponent();
private void ListViewColumnHeaderClick(object sender, RoutedEventArgs e)
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
if (headerClicked == null)
return;
if (headerClicked.Role == GridViewColumnHeaderRole.Padding)
return;
var sortingColumn = (headerClicked.Column.DisplayMemberBinding as Binding)?.Path?.Path;
if (sortingColumn == null)
return;
var direction = ApplySort(Items, sortingColumn);
if (direction == ListSortDirection.Ascending)
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowUp"] as DataTemplate;
else
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowDown"] as DataTemplate;
// Remove arrow from previously sorted header
if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked)
_lastHeaderClicked.Column.HeaderTemplate =
Resources["HeaderTemplateDefault"] as DataTemplate;
_lastHeaderClicked = headerClicked;
public static ListSortDirection ApplySort(ICollectionView view, string propertyName)
ListSortDirection direction = ListSortDirection.Ascending;
if (view.SortDescriptions.Count > 0)
SortDescription currentSort = view.SortDescriptions[0];
if (currentSort.PropertyName == propertyName)
if (currentSort.Direction == ListSortDirection.Ascending)
direction = ListSortDirection.Descending;
else
direction = ListSortDirection.Ascending;
view.SortDescriptions.Clear();
if (!string.IsNullOrEmpty(propertyName))
view.SortDescriptions.Add(new SortDescription(propertyName, direction));
return direction;
【讨论】:
如果你不解释他们在做什么,扔掉数百行代码毫无意义【参考方案8】:只是想添加另一种简单的方法来对 WPF ListView 进行排序
void SortListView(ListView listView)
IEnumerable listView_items = listView.Items.SourceCollection;
List<MY_ITEM_CLASS> listView_items_to_list = listView_items.Cast<MY_ITEM_CLASS>().ToList();
Comparer<MY_ITEM_CLASS> scoreComparer = Comparer<MY_ITEM_CLASS>.Create((first, second) => first.COLUMN_NAME.CompareTo(second.COLUMN_NAME));
listView_items_to_list.Sort(scoreComparer);
listView.ItemsSource = null;
listView.Items.Clear();
listView.ItemsSource = listView_items_to_list;
【讨论】:
【参考方案9】:经过大量搜索,最后我发现这里很简单https://www.wpf-tutorial.com/listview-control/listview-how-to-column-sorting/
private GridViewColumnHeader listViewSortCol = null;
private SortAdorner listViewSortAdorner = null;
private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
GridViewColumnHeader column = (sender as GridViewColumnHeader);
string sortBy = column.Tag.ToString();
if (listViewSortCol != null)
AdornerLayer.GetAdornerLayer(listViewSortCol).Remove(listViewSortAdorner);
yourListView.Items.SortDescriptions.Clear();
ListSortDirection newDir = ListSortDirection.Ascending;
if (listViewSortCol == column && listViewSortAdorner.Direction == newDir)
newDir = ListSortDirection.Descending;
listViewSortCol = column;
listViewSortAdorner = new SortAdorner(listViewSortCol, newDir);
AdornerLayer.GetAdornerLayer(listViewSortCol).Add(listViewSortAdorner);
yourListView.Items.SortDescriptions.Add(new SortDescription(sortBy, newDir));
类:
public class SortAdorner : Adorner
private static Geometry ascGeometry =
Geometry.Parse("M 0 4 L 3.5 0 L 7 4 Z");
private static Geometry descGeometry =
Geometry.Parse("M 0 0 L 3.5 4 L 7 0 Z");
public ListSortDirection Direction get; private set;
public SortAdorner(UIElement element, ListSortDirection dir)
: base(element)
this.Direction = dir;
protected override void OnRender(DrawingContext drawingContext)
base.OnRender(drawingContext);
if(AdornedElement.RenderSize.Width < 20)
return;
TranslateTransform transform = new TranslateTransform
(
AdornedElement.RenderSize.Width - 15,
(AdornedElement.RenderSize.Height - 5) / 2
);
drawingContext.PushTransform(transform);
Geometry geometry = ascGeometry;
if(this.Direction == ListSortDirection.Descending)
geometry = descGeometry;
drawingContext.DrawGeometry(Brushes.Black, null, geometry);
drawingContext.Pop();
Xaml
<GridViewColumn Width="250">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Name" Click="GridViewColumnHeader_Click">Name</GridViewColumnHeader>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="Binding Name" ToolTip="Binding Name"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
【讨论】:
谢谢。加分的话,可以加个解释总结吗?这目前是仅链接和代码(这已经比仅链接更好......)。【参考方案10】:试试这个:
using System.ComponentModel;
youtItemsControl.Items.SortDescriptions.Add(new SortDescription("yourFavoritePropertyFromItem",ListSortDirection.Ascending);
【讨论】:
以上是关于在列标题单击时使 WPF ListView/GridView 排序的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章