WPF Datagrid:使用户能够对列进行排序,但不对它们进行排序

时间:2014-01-02 20:35:35

标签: c# wpf xaml sorting wpfdatagrid

在我的应用程序中,我有一个数据网格,其值经常更新。我希望用户能够单击列进行排序,但是不断应用排序会大大降低我的应用程序速度。有没有办法允许用户进行一次性排序?他们会点击,值会被排序,但如果值发生变化则不会重新排序。

1 个答案:

答案 0 :(得分:2)

如果您将网格绑定到实现 IList 的集合,那么网格将创建一个 ListCollectionView ,用于排序/过滤/分组。从根本上说,您要做的是处理DataGrid的 OnSorting 事件,并告诉您当时想要排序的基础视图,但不是以后;不幸的是,这并不像我尝试时那样容易。

第一种方法如下:

// Do a BeginInvoke here so that the grid can do its default sorting and we can take action after it's complete
this.Dispatcher.BeginInvoke((Action)delegate()
{
    // Get the default view and clear the sort descriptions, but don't fire a refresh notification so that the grid
    // doesn't re-request the view/sorting
    ICollectionView dataView = CollectionViewSource.GetDefaultView(((DataGrid)sender).ItemsSource);               
    dataView.SortDescriptions.Clear();
}, null);

问题是Clear方法告诉网格通过各种属性更改机制刷新其视图。 DeferRefresh 方法在这里没有帮助,因为如果访问数据,视图将抛出异常;这用于更新整个集合的排序。

我不喜欢它,但我能想出的最佳方法是根据用户的操作应用您自己的自定义排序,并使用CustomSort属性将其应用于视图(尽管排序可能更难)多列)。

public class CustomComparer : IComparer
{
    public bool Ascending { get; private set; }
    public string Field { get; private set; }

    public CustomComparer(string fieldName, bool ascending)
    {
        this.Ascending = ascending;
        this.Field = fieldName;
    }

    public int Compare(object x, object y)
    {
        // Ideally check for identical types/etc and IComparable here

        PropertyInfo property = x.GetType().GetProperty(this.Field);
        IComparable val1 = property.GetValue(x) as IComparable;
        IComparable val2 = property.GetValue(y) as IComparable;

        return val1.CompareTo(val2) * (this.Ascending ? 1 : -1);
    }
}

private void DataGrid_OnSorting(object sender, DataGridSortingEventArgs e)
{
    ListCollectionView dataView = (ListCollectionView)CollectionViewSource.GetDefaultView(((DataGrid)sender).ItemsSource);

    // Assumes the column header is identical to field name
    bool ascending = true;
    string fieldName = e.Column.Header.ToString();

    // Check to see if we're reversing the sort
    CustomComparer comparer = dataView.CustomSort as CustomComparer;
    if (comparer != null && comparer.Field == fieldName)
        ascending = !comparer.Ascending;

    e.Column.SortDirection = ascending ? ListSortDirection.Ascending : ListSortDirection.Descending;
    dataView.CustomSort = new CustomComparer(fieldName, ascending);
    dataView.Refresh();
    e.Handled = true;
}

我不喜欢使用反射进行排序,但这是我能够在不为每列创建排序对象的情况下提出的最干净的方法。

对于长篇回复感到抱歉,我认为这有助于解释我的思考过程以及我是如何到达这里的。