DataGrid SortDirection ignored

2019-06-15 04:05发布

问题:

I want to specify a default ordering at startup, but still allow the user to sort by clicking on the column headers. Sadly the SortDirection property is ignored when it is set - i.e. we get the correct column header arrow, but nothing is sorted.

Clicking on the headers manually, sorts the data correctly, so it's not the sorting itself. This is the simplified version I'm using:

<DataGrid ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=CurrentView}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Header 1" Binding="{Binding ApplicationName}"/>
        <DataGridTextColumn Header="Header 2" 
               Binding="{Binding TotalTime}" SortDirection="Descending"/>
    </DataGrid.Columns>
</DataGrid>

Update: I also tried adding SortDescriptions to the ICollectionView as proposed, without good results. Could this have something to do with the fact that I'm dynamically adding new items to the collection? I.e. at startup the list is empty and slowly filled and maybe the sortdescription is only applied once?

回答1:

Take a look at this MSDN Blog

From above link:

DataGridColumn.SortDirection does not actually sort the column.
DataGridColumn.SortDirection is used to queue the visual arrow in the DataGridColumnHeader to point up, down, or to not show. To actually sort the columns other than clicking on the DataGridColumnHeader, you can set the DataGrid.Items.SortDescriptions programmatically.



回答2:

I don't have any personal experience with this, but I found this rather helpful article.

Essentially you need to add a SortDescription to the CollectionViewSource that the DataGrid is bound to.



回答3:

This article was very helpful. I was able to use it to find a somewhat easy solution. Here is a snippet of my solution that worked.

XAML

        <DataGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
            AutoGenerateColumns="False" ItemsSource="{Binding LogLister.Logs}"              
            IsReadOnly="True" >

            <DataGrid.Columns>                  

                <DataGridTextColumn Binding="{Binding TimeStampLocal}" Header="Time" x:Name="ColTimeStamp" />

                <DataGridTextColumn Binding="{Binding Text}" Header="Text"/>
            </DataGrid.Columns>
        </DataGrid>

Code

    // Using a DependencyProperty as the backing store for ViewModel.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(LogViewerViewModel), typeof(LogViewerControl),
           new UIPropertyMetadata(null,pf_viewModelChanged));

    private static void pf_viewModelChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var control = (LogViewerControl)o;

        control.ColTimeStamp.SortDirection = ListSortDirection.Descending;

        var vm = e.NewValue as LogViewerViewModel;

        if (vm != null)
        {   
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(vm.LogLister.Logs);
            collectionView.SortDescriptions.Add(new SortDescription("TimeStampLocal", ListSortDirection.Descending));
        }
    }


回答4:

The short of it is that there is no quick, easy way to do it. I wrote my own custom sorter that uses the Move method on ObservableCollections. I override the "DataGridSorting" event and call my own methods to facilitate this. I am not going to post the code here because I think it's too overblown for your question.

I would say stick with my above comment by using a CollectionViewSource and a SortDescription (competent_tech originally posted).