如何在排序后始终将 DataGrid 的一行或多行保持在顶部

本文关键字:一行 顶部 排序 DataGrid | 更新日期: 2023-09-27 17:55:21

我有一个 DataGrid(在视图上)绑定到一个 ObservableCollection(在视图模型上)。

对于这个 ObservableCollection,我以编程方式添加一个"魔术行",因为所选项目将用于对其他地方的另一个集合进行排序,我添加此虚拟行以"清除"过滤。

目前,当视图加载时,我的魔术字符串总是出现在顶部(因为我将其插入索引 0 ),但是一旦我单击标题更改排序顺序,行就会按字母顺序重新排列,我的魔术行就消失在瓦砾中。

想要的是魔术行始终显示在顶部,即使我单击标题以更改排序顺序也是如此。

视图模型:

// (...)
public ObservableCollection<FilteringItem> ItemTypes
{
    get
    {
        var result = new ObservableCollection<FilteringItem>(_setups.Select(n => n.ItemType)
                                                             .Distinct()
                                                             .Select(s => new FilteringItem(s, s))
                                                             .OrderBy(v => v.Name));

        // Magic Happens Here: adding a "magic" row to remove filtering
        // (that is, "allow all") when used by some filtering method elsewhere;
        string allString = String.Format("All ({0})", result.Count);
        var filteringAll = new FilteringItem(allString, "");
        result.Insert(0, filteringAll);
        return result;
    }
}
// (...)
public class FilteringItem
{
    public string Name { get; private set; }
    public string Value { get; private set; }
    public FilteringItem(string name, string val)
    {
        Name = name;
        Value = val;
    }
}    

视图:

<DataGrid ItemsSource="{Binding ItemTypes}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Tipo" Width="*" Binding="{Binding Name}"/>
    </DataGrid.Columns>
</DataGrid>

如何在排序后始终将 DataGrid 的一行或多行保持在顶部

亏了这篇博文,我让它工作了。

"秘密"是截获Sorting事件(将e.Handled设置为true),然后将 DataGrid.ItemsSource 强制转换为ListCollectionView,然后将自定义IComparer分配给ListCollectionView.CustomSort属性。

然后,在排序时,您以某种方式识别您的固定行(在我的情况下,通过 null 值),并使其始终位于顶部(这反过来又取决于ListSortDirection)。

public partial class ViewContainingDataGrid : UserControl
{
    public ViewContainingDataGrid()
    {
        this.InitializeComponent();
    }
    private void datagrid_Sorting(object sender, DataGridSortingEventArgs e)
    {
        e.Handled = true;
        SmartSort(sender, e.Column);
    }
    private void SmartSort(object sender, DataGridColumn column)
    {
        ListSortDirection direction = (column.SortDirection != ListSortDirection.Ascending) ?
                             ListSortDirection.Ascending : ListSortDirection.Descending;
        column.SortDirection = direction;
        var dg = sender as DataGrid;
        var lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(dg.ItemsSource);
        lcv.CustomSort = new SmartSorter(direction);
    }
}
public class SmartSorter : IComparer
{
    public ListSortDirection Direction { get; private set; }
    public SmartSorter(ListSortDirection direction)
    {
        Direction = direction;
    }

    public int Compare(object x, object y)
    {
        string valorx = x as string;
        string valory = y as string;
        int comparison = valorx.CompareTo(valory);
        if (Direction == ListSortDirection.Descending)
            comparison *= -1;
        // Override the sorting altogether when you find the special row value
        if (String.IsNullOrWhiteSpace(valorx))
            comparison = -1;
        else
        if (String.IsNullOrWhiteSpace(valory))
            comparison = 1;
        return comparison;
    }
}