请记住 WPF 数据网格排序顺序

本文关键字:网格 排序 顺序 数据网 数据 WPF | 更新日期: 2023-09-27 18:31:24

这是这个问题的延续。

1. 设置

我有一个 wpf 窗口,其中包含一个带有动态创建项的TabControl。此TabControlItemSource绑定到Group的列表。这些组包含显示在TabPage上的DataGrid中的元素列表。

XAML:

<Window x:Name="window" x:Class="TestWpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:TestWpf"
    Title="MainWindow" Height="350" Width="525">
    <TabControl x:Name="tabControl" BorderThickness="0" ItemsSource ="{Binding Groups, ElementName=window, NotifyOnSourceUpdated=True}">
        <TabControl.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:Group}">
                <TextBlock Padding="2" Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate x:Name="contentTemplate" DataType="{x:Type vm:Group}">
                <DataGrid x:Name="dgElements" ItemsSource="{Binding Elements, BindsDirectlyToSource=True}" DockPanel.Dock="Top" AutoGenerateColumns="False" >
                    <DataGrid.Columns>
                        <DataGridTextColumn x:Name="clmName" Header="Name" Binding="{Binding Name}" IsReadOnly="True" CanUserReorder="False" />
                    <DataGridTextColumn x:Name="clmDesc" Header="Description" Binding="{Binding Description}" IsReadOnly="True" CanUserReorder="False" />
                    </DataGrid.Columns>
                </DataGrid>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Window>

这一切都很好用。

2. 问题

DataGrid允许开箱即用的多列排序。但不幸的是,如果我在标签页之间切换,排序就会丢失。
我希望为每个选项卡页/数据网格维护多列排序

可以将DataGridTextColumnSortDirection绑定到属性,但这不会记住列的排序顺序。调试时我发现当我切换标签页时,SortDirection在设置新ItemSource之前被重置,所以我无法存储它。

问题是:如何保留每个选项卡页/数据网格的多列排序设置?

请记住 WPF 数据网格排序顺序

在阅读了很多文章几乎解决了我的问题后,我终于找到了解决方案。
我从DataGrid继承了自己的类,并将每ItemSource SortDescriptions存储在Dictionary中:

public class SortKeepingDataGrid : DataGrid
{
    // Dictionary to keep SortDescriptions per ItemSource
    private readonly Dictionary<object, List<SortDescription>> m_SortDescriptions =
        new Dictionary<object, List<SortDescription>>();
    protected override void OnSorting(DataGridSortingEventArgs eventArgs)
    {
        base.OnSorting(eventArgs);
        UpdateSorting();
    }
    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);
        ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
        view.SortDescriptions.Clear();
        // reset SortDescriptions for new ItemSource
        if (m_SortDescriptions.ContainsKey(newValue))
            foreach (SortDescription sortDescription in m_SortDescriptions[newValue])
            {
                view.SortDescriptions.Add(sortDescription);
                // I need to tell the column its SortDirection,
                // otherwise it doesn't draw the triangle adornment
                DataGridColumn column = Columns.FirstOrDefault(c => c.SortMemberPath == sortDescription.PropertyName);
                if (column != null)
                    column.SortDirection = sortDescription.Direction;
            }
    }
    // Store SortDescriptions in dictionary
    private void UpdateSorting()
    {       
        ICollectionView view = CollectionViewSource.GetDefaultView(ItemsSource);
        m_SortDescriptions[ItemsSource] = new List<SortDescription>(view.SortDescriptions);
    }
}

因此,基本上,每当用户更改排序时,我都会调用UpdateSorting并将当前SortDescription存储在每ItemSource字典中。
ItemSource发生变化时,我会查找SortDescription并按正确的顺序重置它们。

棘手的部分是找到正确的DataGridColumn来设置其SortDirection 。这对于绘制三角形装饰是必要的。我在这里依靠SortMemberPathPropertyName的平等.最终可能需要一种更通用的方法。

在 XAML 中,我用SortKeepingDataGrid替换了DataGrid,现在排序按选项卡页存储。

由于我找不到任何其他解决方案,也许这也会对其他人有所帮助。