如何实现(最好是纯粹在XAML中)WPF DataGrid的列标题中的排序标记与CollectionViewSource中的当前排序顺序同步?
例如,我有以下示例代码,它显示C:\中所有文件的属性,按长度排序:
<Window x:Class="DataGridSortTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="items" Source="{Binding Files}">
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="Length"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Source={StaticResource items}}"/>
</Grid>
</Window>
MainWindow.xaml.cs中的代码隐藏是:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Files = Directory.GetFiles(@"C:\").Select(f => new FileInfo(f)).ToList();
DataContext = this;
}
public IEnumerable<FileInfo> Files { get; private set; }
}
当我开始这个程序时,它看起来像这样:
即。文件正确排序,但标题中的标记丢失。使用“marker”,我的意思是:
注意:我正在寻找通用解决方案。仅设置DataGridColumn.SortDirection
不是解决方案。我正在寻找一种方法来指示DataGrid从集合视图中自动检索排序顺序。
答案 0 :(得分:1)
这似乎是一个古老的问题,但今天我遇到了同样的问题,并找到了一个通用的解决方案。因此,想法是SortDescriptions集合隐式实现INotifyCollectionChanged,因此我们有能力观察它并设置DataGrid&#34;排序标记&#34;适当。我在单独的行为中实现了这个:
public class DataGridSortDescriptionsSyncBehavior : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
var view = CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource);
var notifyCollection = view.SortDescriptions as INotifyCollectionChanged;
if (notifyCollection != null)
notifyCollection.CollectionChanged += SortDescriptions_CollectionChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
var view = CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource);
var notifyCollection = view.SortDescriptions as INotifyCollectionChanged;
if (notifyCollection != null)
notifyCollection.CollectionChanged -= SortDescriptions_CollectionChanged;
}
private void SortDescriptions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
// clear all columns sort directions
foreach (var column in AssociatedObject.Columns)
column.SortDirection = null;
}
if (e.NewItems != null)
{
// set columns sort directions
foreach (SortDescription descr in e.NewItems)
SetSortDirection(descr.PropertyName, descr.Direction);
}
if (e.OldItems != null)
{
// reset columns sort directions
foreach (SortDescription descr in e.OldItems)
SetSortDirection(descr.PropertyName, null);
}
}
private void SetSortDirection(string sortMemberPath, ListSortDirection? direction)
{
var column = AssociatedObject.Columns.FirstOrDefault(c => c.SortMemberPath == sortMemberPath);
if (column != null)
{
column.SortDirection = direction;
}
}
}
对于那些不了解行为的人 - 您需要添加对System.Windows.Interactivity程序集的引用并将行为应用于DataGrid:
<DataGrid ItemsSource="{Binding Data}">
<i:Interaction.Behaviors>
<local:DataGridSortDescriptionsSyncBehavior />
</i:Interaction.Behaviors>
</DataGrid>
现在,当您修改集合时,&#34;排序标记&#34;自动调整。此外,请注意,此行为仅适用于默认集合视图。如果您正在使用显式创建的集合视图 - 只需将其发送到行为(例如,通过行为&#39; s属性)并使用它而不是默认集合视图。
答案 1 :(得分:0)
对于您的通用解决方案,我有两个提案。
首先:
您可以创建新的DataGrid类并自动检查SortDescriptions。
class ExDataGrid : DataGrid
{
bool isFirstRow = true;
protected override void OnLoadingRow(DataGridRowEventArgs e)
{
base.OnLoadingRow(e);
if (isFirstRow)
SortDirectionHelper(this);
}
private void SortDirectionHelper(DataGrid dg)
{
var tmp = dg.Items.SortDescriptions;
foreach (SortDescription sd in tmp)
{
var col = dg.Columns.Where(x => (((Binding)x.ClipboardContentBinding).Path.Path == sd.PropertyName)).FirstOrDefault();
if (col != null)
{
col.SortDirection = sd.Direction;
}
}
isFirstRow = false;
}
}
Xaml文件:
<Window x:Class="DataGridSortTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Title="MainWindow" Height="350" Width="525"
xmlns:dg="clr-namespace:DataGridSortTest"
>
<Window.Resources>
<CollectionViewSource x:Key="items" Source="{Binding Files}" >
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="Length"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<dg:ExDataGrid x:Name="grid" ItemsSource="{Binding Source={StaticResource items}}" />
</Grid>
</Window>
<强>第二强>
您可以在每个网格中为Loaded事件创建EventHandler
private void grid_Loaded(object sender, RoutedEventArgs e)
{
SortDirectionHelper(sender as DataGrid);
}
public void SortDirectionHelper(DataGrid dg)
{
var tmp = dg.Items.SortDescriptions;
foreach (SortDescription sd in tmp)
{
var col = dg.Columns.Where(x => (((Binding)x.ClipboardContentBinding).Path.Path == sd.PropertyName)).FirstOrDefault();
if (col != null)
{
col.SortDirection = sd.Direction;
}
}
}
答案 2 :(得分:0)
来自msdn论坛
您需要在DataGrid上显式指定SortDirection属性 用于使标记显示在列标题中的列,如 标记功能是DataGrid不绑定源。
所以也许你最好使用@kmatyaszek解决方案