CollectionViewSource 仅在第一次绑定到源时排序
我正在使用绑定到 CollectionViewSource(玩家)的 DataGrid,它本身绑定到 ListBox 当前选定的项目(级别),每个项目都包含要排序的集合/在DataGrid中显示:
<ListBox Name="lstLevel"
DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True" />
……
<!-- DataGrid source, as a CollectionViewSource to allow for sorting and/or filtering -->
<CollectionViewSource x:Key="Players"
Source="{Binding ElementName=lstLevel,
Path=SelectedItem.Players}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
"
<DataGrid Name="lstPlayers" AutoGenerateColumns="False"
CanUserSortColumns="False"
ItemsSource="{Binding Source={StaticResource Players}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Path=Name, Mode=TwoWay}"
Width="*" />
<DataGridTextColumn Header="Age"
Binding="{Binding Path=Age, Mode=TwoWay}"
Width="80">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
(整个C#代码此处,XAML代码此处,整个测试项目 此处 - 除了 DataGrid 之外,我还为玩家添加了一个简单的 ListBox,以确保这不是 DataGrid 问题)
问题是玩家第一次排序显示,但一旦我从列表框中选择另一个级别,它们就不再排序。此外,第一次显示玩家时修改名称会根据更改对他们进行排序,但一旦级别更改,就不会再排序了。
因此,看起来更改 CollectionViewSource 的源以某种方式破坏了排序功能,但我不知道为什么,也不知道如何修复它。有谁知道我做错了什么?
(我使用过滤器进行了测试,但该过滤器继续按预期工作)
框架是 .NET 4。
I'm using a DataGrid bound to a CollectionViewSource (players), itself bound to the currently selected item of a ListBox (levels), each item containing a collection to be sorted/displayed in the DataGrid:
<ListBox Name="lstLevel"
DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True" />
...
<!-- DataGrid source, as a CollectionViewSource to allow for sorting and/or filtering -->
<CollectionViewSource x:Key="Players"
Source="{Binding ElementName=lstLevel,
Path=SelectedItem.Players}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
...
<DataGrid Name="lstPlayers" AutoGenerateColumns="False"
CanUserSortColumns="False"
ItemsSource="{Binding Source={StaticResource Players}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Path=Name, Mode=TwoWay}"
Width="*" />
<DataGridTextColumn Header="Age"
Binding="{Binding Path=Age, Mode=TwoWay}"
Width="80">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
(whole C# code here, XAML code here, entire test project here - in addition to the DataGrid I've added a simple ListBox for the players, to make sure it wasn't a DataGrid issue)
The problem is that the players are sorted the first time they are shown, but as soon as I select another level from the ListBox, they are not sorted anymore. Also, modifying names the first time players are shown will sort them accordingly to the changes, but not anymore once the level has been changed.
So it looks like changing the source of the CollectionViewSource somehow breaks the sort feature, but I have no idea why, nor how to fix it. Does anyone know what I'm doing wrong?
(I did a test with a filter, but that one kept working as expected)
The framework is .NET 4.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
很好的问题和有趣的观察。仔细检查后发现,DataGrid 在设置新 ItemsSource 之前会清除先前 ItemsSource 的排序描述。以下是 OnCoerceItemsSourceProperty 的代码:
此行为仅发生在 DataGrid 上。如果您改用 ListBox(以显示上面的“Players”集合),则行为将会有所不同,并且在从父数据网格中选择不同的项目后,SortDescriptions 仍将保留。
所以我想解决这个问题的方法是每当父 DataGrid 中的所选项目(即“lstLevel”)发生变化时,以某种方式重新应用 Players 集合的排序描述。
然而,我对此并不是 100% 确定,可能需要更多的测试/调查。我希望我能够做出一些贡献。 =)
编辑:
作为建议的解决方案,您可以在设置 lstLevel.ItemsSource 属性之前在构造函数中放置 lstLevel.SelectionChanged 的处理程序。像这样的事情:
EDIT2:
为了响应您在键盘导航方面遇到的问题,我建议您不要处理“CurrentChanged”事件,而是处理 lstLevel.SelectionChanged 事件。我在下面发布了您需要进行的必要更新。只需复制粘贴到您的代码中,看看它是否正常工作。
XAML:
代码隐藏(构造函数):
Great question and an interesting observation. Upon closer inspection, it appears that the DataGrid clears sort descriptions of a previous ItemsSource before a new one is set. Here is its code for OnCoerceItemsSourceProperty:
This behavior only happens on a DataGrid. If you used a ListBox instead (to display the "Players" collection above), the behavior will be different and the SortDescriptions will still remain after selecting different items from the parent datagrid.
So I guess the solution to this is to somehow re-apply the sort descriptions of the Players collection whenever the selected item in the parent DataGrid (i.e. "lstLevel") changes.
However, I'm not 100% sure about this and probably needs more testing/investigation. I hope I was able to contribute something though. =)
EDIT:
As a suggested solution, you can put a handler for lstLevel.SelectionChanged in your constructor, before setting the lstLevel.ItemsSource property. Something like this:
EDIT2:
In response to the problems you're encountering with regards to keyboard navigation, I suggest that instead of handling the "CurrentChanged" event, you handle the lstLevel.SelectionChanged event instead. I'm posting the necessary updates you need to make below. Just copy-paste to your code and see if it works fine.
XAML:
Code-behind (constructor):
更好的解决方法:
CollectionViewSource 仅在第一次绑定到源时排序
A better workaround:
CollectionViewSource sorting only the first time it is bound to a source
我可以通过简单地在公开视图的属性上调用 PropertyChanged、让视图刷新(并清除排序)然后添加排序描述来解决此问题。
I was able to fix this by simply calling PropertyChanged on the property that exposes the view, letting the view refresh (and clear out the sort) and then adding the sort descriptions.