互联网上有许多解决方案,试图弥补WPF似乎很基础的遗漏。对于“最佳”方式,我确实感到困惑。例如...我希望列标题中有向上/向下的小箭头,以指示排序方向。显然,有3种不同的方法可以执行此操作,有些使用代码,某些使用标记,某些使用标记加代码,而所有这些似乎都像是黑客。
有没有人遇到过这个问题,找到了他们完全满意的解决方案?WPF缺少这样一个基本的WinForms功能似乎很奇怪,需要加以破解。
互联网上有许多解决方案,试图弥补WPF似乎很基础的遗漏。对于“最佳”方式,我确实感到困惑。例如...我希望列标题中有向上/向下的小箭头,以指示排序方向。显然,有3种不同的方法可以执行此操作,有些使用代码,某些使用标记,某些使用标记加代码,而所有这些似乎都像是黑客。
有没有人遇到过这个问题,找到了他们完全满意的解决方案?WPF缺少这样一个基本的WinForms功能似乎很奇怪,需要加以破解。
Answers:
这完全取决于实际情况,如果您使用的是WPF工具包中的DataGrid,则有一个内置的排序方式,甚至是多列排序方式也非常有用。在这里查看更多信息:
另外,如果您使用的其他控件不支持排序,则建议您使用以下方法:
其次是:
我编写了一组附加属性来对a进行自动排序GridView
,您可以在此处进行检查。它不处理上/下箭头,但可以轻松添加。
<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>
CollectionViewSource.GetDefaultView(MyList.ItemsSource).SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));
不起作用。
MSDN提供了一种简单的方法来对带有上/下字形的列进行排序。但是,该示例并不完整-他们没有解释如何使用字形的数据模板。以下是我要使用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中,需要添加在排序方法中指定的两个DataTemplates:
<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
withLastChildFill
设置为true可以将字形保留在标题的右侧,并让标签填充其余的空间。我将DockPanel
宽度限制为的ActualWidth
,GridViewColumnHeader
因为我的列没有宽度,这使它们可以自动适应内容。但是,我确实MinWidth
在列上设置了s,以便该字形不会掩盖列标题。将TextBlock Text
设置为空绑定,该绑定显示标题中指定的列名。
<Window.Resources>
或<UserControl.Resources>
。HTHS;)
headerClicked.Column.Header
(是标题文本)与(headerClicked.Column.DisplayMemberBinding as Binding).Path.Path
(是绑定路径)等效。无法对标题文本进行排序。很奇怪。
我使用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;
}
}
}
我对Microsoft的方式进行了改编,在其中我重写了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"
然后在Window
包含任何数量SortableListView
s的任何对象上,只需添加以下代码:
private void SortableListViewColumnHeaderClicked(object sender, RoutedEventArgs e)
{
((Controls.SortableListView)sender).GridViewColumnHeaderClicked(e.OriginalSource as GridViewColumnHeader);
}
哪里Controls
是您在其中进行SortableListView
控件的名称空间的XAML ID 。
因此,这确实防止了排序方面的代码重复,您只需要记住要像上面那样处理该事件即可。
如果您拥有一个列表视图并将其转换为一个网格视图,则可以轻松地使您的网格视图列标题可单击。
<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中保留所有View。
我仅添加了此内容,以便有多种方法可以完成同一件事。我没有编写用于在标题中添加箭头按钮的代码,但这将以XAML样式完成,您将需要重新设计JanDotNet在其代码中具有的整个标题。
视图:
<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;
}
}
只是想添加其他人可以对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;
}
经过大量搜索,最终我发现这里很简单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>