C# 如何使数据网格中的一行或多行即使在排序后也始终位于顶部

C# 如何使数据网格中的一行或多行即使在排序后也始终位于顶部,c#,wpf,sorting,datagrid,C#,Wpf,Sorting,Datagrid,我有一个DataGrid(在视图上)绑定到一个ObservableCollection(在ViewModel上) 对于这个ObservableCollection,我以编程方式添加了一个“魔行”,因为选中的项将用于对其他地方的另一个集合进行排序,我添加这个伪行以“清除”筛选 当前,当视图加载时,我的魔术字符串始终显示在顶部(因为我将其插入索引0),但只要我单击标题以更改排序顺序,行就会按字母顺序重新排列,我的魔术行就会消失在废墟中 我想要的是,魔术行始终显示在顶部,即使当我点击标题更改排序顺序时

我有一个DataGrid(在视图上)绑定到一个ObservableCollection(在ViewModel上)

对于这个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;
    }
}    
/(…)
公共ObservableCollection项类型
{
得到
{
var结果=新的ObservableCollection(_setups.Select(n=>n.ItemType)
.Distinct()
.选择(s=>new FilterGitem)
.OrderBy(v=>v.Name));
//神奇的事情发生在这里:添加一个“神奇”行以删除过滤
//(即,“允许全部”)当由其他地方的某些过滤方法使用时;
string allString=string.Format(“All({0})”,result.Count);
var filteringAll=new FilteringItem(allString,“”);
结果。插入(0,filteringAll);
返回结果;
}
}
// (...)
公共类筛选器Gitem
{
公共字符串名称{get;private set;}
公共字符串值{get;private set;}
公共筛选器gitem(字符串名称、字符串值)
{
名称=名称;
值=val;
}
}    
视图:


多亏了你,我才让它正常工作

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

然后,在排序时,您以某种方式标识固定行(在我的例子中,通过空值),并使其始终位于顶部(这反过来取决于
ListSortDirection

<DataGrid ItemsSource="{Binding ItemTypes}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Tipo" Width="*" Binding="{Binding Name}"/>
    </DataGrid.Columns>
</DataGrid>
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;
    }
}