WPF DataGrid 默认排序不起作用

问题描述 投票:0回答:2

我有一个 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" />

我将其绑定到

ObservableCollection<EalsLogEvent>
,其中输入
EalsLogEvent.Date
DateTime
:

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

网格视图模型使用计时器来刷新自身,网格的一切看起来都很好,除了在应用程序启动时首次加载时。然后,

Time
列似乎按降序排序,但实际上是按升序排序。

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

如果我在

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

wpf xaml mvvm datagrid wpfdatagrid
2个回答
19
投票

您可以在 XAML 中使用

CollectionViewSource
来定义默认排序。

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

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

我们可以为

CollectionView
集合创建自定义
Items

<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>

使用这种方法,您的底层源集合(本例中为

Items
)将不会受到影响,排序仅发生在视图中。

正如您可以在 MSDN 中阅读的那样:

您可以将集合视图视为绑定顶部的层 源集合,允许您导航和显示 基于排序、过滤和分组查询的集合,全部无需 必须操纵底层源集合本身。如果 源集合实现了 INotifyCollectionChanged 接口, CollectionChanged 事件引发的更改将传播到 意见。

您还应该注意以下事项:

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

因此,使用

CollectionViewSource
,您只需为您的集合定义一个自定义视图。


0
投票

您应该在视图模型中创建 2 个属性:

private ObservableCollection<EalsLogEvent> logEvents = new ObservableCollection<EalsLogEvent>();
private ICollectionView logEventsView;

public ObservableCollection<EalsLogEvent> LogEvents
{
    get { return this.logEvents; }
    set { this.SetProperty(ref this.logEvents, value); }
}

public ICollectionView LogEventsView
{
    get
    {
        if (this.logEventsView == null)
        {
            this.logEventsView= CollectionViewSource.GetDefaultView(this.LogEvents);
            this.logEventsView.SortDescriptions.Add(new SortDescription("Time", ListSortDirection.Descending));
        }

        return this.logEventsView;
    }
}

将 DataGrid 绑定到

LogEventsView
,并使用
LogEvents
添加或删除项目。 这允许默认排序和用户排序。

© www.soinside.com 2019 - 2024. All rights reserved.