记住 WPF 数据表格的排序顺序

3
这是这个问题的延续。

1. 设置

我有一个WPF窗口,其中包含一个动态创建项目的TabControl。 此TabControlItemSource绑定到Group列表。 这些组包含在上显示的元素列表中的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被设置之前重置了,因此我无法存储此信息。

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

1个回答

12

在阅读了许多文章并几乎解决了我的问题后,我终于找到了一个解决方案。
我从 DataGrid 继承了自己的类,并将每个 ItemSourceSortDescriptions 存储在一个 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,现在排序按选项卡页存储。
由于我找不到其他解决方案,也许这对其他人有所帮助。

1
我需要告诉该列它的SortDirection,否则它不会绘制三角形装饰。这个注释帮助我理解为什么我的DataGrid中排序箭头消失了。谢谢。 - Jach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接