问题描述
我有一个 DataGrid,其中包含 XAML 列:
I have a DataGrid, with columns XAML as such:
<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.Date
的类型是 DateTime
:
I bind this to an ObservableCollection<EalsLogEvent>
, where EalsLogEvent.Date
is typed DateTime
:
public ObservableCollection<EalsLogEvent> LogEvents
{
get
{
return _logEvents;
}
}
网格视图模型使用计时器来刷新自身,网格看起来一切正常,除了在应用程序启动时首次加载时.然后,Time
列似乎按降序排序,但按升序排序.
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 Time
column appears to be sorted descending, but is sorted ascending.
要正确排序,我必须单击列标题两次;第一次将顺序更改为升序,现在与列的内容匹配.第二次点击列标题将其排序顺序改回降序,这次它正确地对列内容进行排序,即降序.
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.
如果我在 _logEvents
刷新时使用 LINQ 对集合进行排序,我会丢失用户通过单击列标题为该列设置的任何顺序.如果我必须让视图告诉模型 LINQ 排序应该使用哪个顺序,那么有些东西会很糟糕.
If I use LINQ to order the collection when _logEvents
gets 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.
推荐答案
您可以在 XAML 中使用 CollectionViewSource
来定义默认排序.
You could use a CollectionViewSource
in your XAML to define the default sorting.
假设我们有一个视图模型:
Assuming we have a view model:
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; private set; }
}
我们可以为 Items
集合创建一个自定义的 CollectionView
:
We can create a custom CollectionView
for the Items
collection:
<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
)不会受到影响,排序仅发生在视图中.
With this approach, your underlying source collection (Items
in this example) will not be affected, the sorting occurs only in the view.
正如您在 MSDN:
您可以将集合视图视为绑定之上的层源集合,允许您导航和显示基于排序、过滤和分组查询的集合,所有这些都没有必须操作底层源集合本身.如果源集合实现了 INotifyCollectionChanged 接口,CollectionChanged 事件引发的更改将传播到意见.
您还应该注意以下几点:
You should also note the following:
所有集合都有一个默认的 CollectionView.WPF 总是绑定到查看而不是集合.如果你直接绑定到一个集合,WPF 实际上绑定到该集合的默认视图.
因此,使用 CollectionViewSource
,您只需为您的集合定义自定义视图.
So, using the CollectionViewSource
, you're just defining a custom view for your collection.
这篇关于WPF DataGrid 默认排序不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!