WPF DataGrid 默认排序不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28985125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:00:05  来源:igfitidea点击:

WPF DataGrid default sort not working

wpfxamlmvvmdatagridwpfdatagrid

提问by ProfK

I have a DataGrid, with columns XAML as such:

我有一个 DataGrid,其中包含 XAML 列,如下所示:

<DataGridTextColumn Header="Time" Binding="{Binding Date, StringFormat='yyyy-MM-dd  HH:mm:ss'}" SortMemberPath="Date" SortDirection="Descending" Width="130" CanUserResize="True" />
<DataGridTextColumn Header="Level" Binding="{Binding Level}" Width="60" CanUserResize="True" />
<DataGridTextColumn Header="Source" Binding="{Binding Logger}" Width="150" CanUserResize="True" />
<DataGridTextColumn Header="Message" Binding="{Binding Message}" Width="*" CanUserResize="True" />

I bind this to an ObservableCollection<EalsLogEvent>, where EalsLogEvent.Dateis typed DateTime:

我将其绑定到 an ObservableCollection<EalsLogEvent>,其中EalsLogEvent.Date键入DateTime

public ObservableCollection<EalsLogEvent> LogEvents 
{
    get
    {
        return _logEvents;
    }
}

The grid viewmodel uses a timer to refresh itself, and everything seems fine with the grid, except when it first loads, on app startup. Then, the Timecolumn appears to be sorted descending, but is sorted ascending.

网格视图模型使用一个计时器来刷新自身,网格的一切似乎都很好,除了在应用程序启动时首次加载时。然后,该Time列似乎按降序排序,但按升序排序。

To get the sort right, I must click the column header twice; the first time changes the order to ascending, which now matches the content of the column. The second click on the column header changes its sort order back to descending, and this time it sorts the column contents properly, i.e. descending.

为了正确排序,我必须单击列标题两次;第一次将顺序更改为升序,现在与列的内容匹配。第二次单击列标题会将其排序顺序更改回降序,这一次它正确地对列内容进行排序,即降序。

If I use LINQ to order the collection when _logEventsgets refreshed, I lose whichever order the user had set for the column by clicking its header. If I have to have the view tell the model which order the LINQ sort should use, something smells bad.

如果我_logEvents在刷新时使用 LINQ 对集合进行排序,我会丢失用户通过单击列标题为该列设置的任何顺序。如果我必须让视图告诉模型 LINQ 排序应该使用哪个顺序,那么有些东西闻起来很糟糕。

回答by dymanoid

You could use a CollectionViewSourcein your XAML to define the default sorting.

您可以CollectionViewSource在 XAML 中使用 a来定义默认排序。

Assuming we have a view model:

假设我们有一个视图模型:

public class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Item> Items { get; private set; }
}

We can create a custom CollectionViewfor the Itemscollection:

我们可以CollectionViewItems集合创建自定义:

<Window xmlns:l="clr-namespace:YourNamespace"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase">
    <Window.DataContext>
        <l:ViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <CollectionViewSource Source="{Binding Items}" x:Key="GridItems">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Date" Direction="Descending"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <DataGrid ItemsSource="{Binding Source={StaticResource GridItems}}" AutoGenerateColumns="False">
        <DataGrid.Columns>                    
            <DataGridTextColumn Header="Time" Binding="{Binding Date, StringFormat='yyyy-MM-dd  HH:mm:ss'}" Width="130" CanUserResize="True" />
            <DataGridTextColumn Header="Level" Binding="{Binding Level}" Width="60" CanUserResize="True" />
            <DataGridTextColumn Header="Source" Binding="{Binding Logger}" Width="150" CanUserResize="True" />
            <DataGridTextColumn Header="Message" Binding="{Binding Message}" Width="*" CanUserResize="True" />
        </DataGrid.Columns>
    </DataGrid>
</Window>

With this approach, your underlying source collection (Itemsin this example) will not be affected, the sorting occurs only in the view.

使用这种方法,您的底层源集合(Items在本例中)不会受到影响,排序仅发生在视图中。

As you can read in MSDN:

正如您在MSDN 中所读到的:

You can think of a collection view as the layer on top of the binding source collection that allows you to navigate and display the collection based on sort, filter, and group queries, all without having to manipulate the underlying source collection itself. If the source collection implements the INotifyCollectionChanged interface, the changes raised by the CollectionChanged event are propagated to the views.

您可以将集合视图视为绑定源集合之上的层,它允许您基于排序、过滤和分组查询来导航和显示集合,而无需操作底层源集合本身。如果源集合实现 INotifyCollectionChanged 接口,则 CollectionChanged 事件引发的更改将传播到视图。

You should also note the following:

您还应该注意以下几点:

All collections have a default CollectionView. WPF always binds to a view rather than a collection. If you bind directly to a collection, WPF actually binds to the default view for that collection.

所有集合都有一个默认的 CollectionView。WPF 始终绑定到视图而不是集合。如果直接绑定到集合,WPF 实际上会绑定到该集合的默认视图。

So, using the CollectionViewSource, you're just defining a custom view for your collection.

因此,使用CollectionViewSource,您只需为您的集合定义自定义视图。