我有一个类“ Widget”的集合,该类具有属性Name(字符串)和Rank(int)。我正在我的视图模型中创建一个CollectionViewSource实例,该实例按Rank然后按Name声明排序顺序。在我的视图模型构造函数中,我正在创建三个小部件,这些小部件中Rank产生的顺序与Name产生的顺序相反。
这是我的主要视图模型代码:
class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void FirePropertyChanged(string property)
{
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private CollectionViewSource _widgetView;
public CollectionViewSource WidgetView
{
get { return _widgetView; }
set { _widgetView = value; }
}
public MainViewModel()
{
WidgetView = new CollectionViewSource();
WidgetView.IsLiveSortingRequested = true;
WidgetView.SortDescriptions.Add(new SortDescription("Rank", ListSortDirection.Ascending));
WidgetView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
WidgetView.Source = new ObservableCollection<Widget>()
{
new Widget() { Name = "W_1", Rank = 3 },
new Widget() { Name = "W_2", Rank = 2 },
new Widget() { Name = "W_3", Rank = 1 },
}; ;
}
}
我的MainWindow.xaml看起来像这样。
<Window x:Class="CollectionViewSortingBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CollectionViewSortingBug"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Button DockPanel.Dock="Bottom" Content="New View Model" Name="newViewModelButton" Click="newViewModelButton_Click" />
<DataGrid Name="dgv" ItemsSource="{Binding WidgetView.View}" AutoGenerateColumns="False" CanUserSortColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" />
<DataGridTextColumn Binding="{Binding Rank}" Header="Rank" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
点击处理程序在窗口后面的代码是这样的:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void newViewModelButton_Click(object sender, RoutedEventArgs e)
{
DataContext = new MainViewModel();
}
}
最后,这是Widget.cs代码:
class Widget : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void FirePropertyChanged(string property)
{
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
FirePropertyChanged("Name");
}
}
private int _rank;
public int Rank
{
get { return _rank; }
set
{
_rank = value;
FirePropertyChanged("Rank");
}
}
}
如您所见,当我单击按钮时,将构建一个新的MainViewModel并将MainWindow的DataContext分配给该新实例。第一次单击按钮时,一切都会按预期运行,这在我的表中:
| Name | Rank |
|------|------|
| W_3 | 1 |
| W_2 | 2 |
| W_1 | 3 |
如果我编辑Rank值,行将相应移动。例如,如果我将W_2的等级设置为10,它将移到W_1以下。如果我将所有Rank值都设置为相等,然后更改名称,则表格将按预期按新名称的字母顺序进行排序。
但是,如果我再次单击该按钮,该表现在将按名称排序。
| Name | Rank |
|------|------|
| W_1 | 3 |
| W_2 | 2 |
| W_3 | 1 |
并且更改等级或名称值无效。好像所有排序逻辑都已清除,实时排序根本不再发生。
当DataContext更改时,行为为何不同?
更新: 我用具有类似功能(名称和等级的文本框)的ItemsControl替换了DataGrid,并且它继续按我希望的方式通过CollectionViewSource进行排序(即它没有出现此问题)。所有其他代码是相同的。这是我将DataGrid块替换为:
<ItemsControl Name="ic" ItemsSource="{Binding WidgetView.View}" DockPanel.Dock="Bottom">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Widget}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Name}" Width="100"/>
<TextBox Text="{Binding Rank}" Width="75"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
奇怪的是,如果我把 both 控件留在那儿(堆叠在DockPanel中),那么 both 控件又会坏掉。这可能是一个实际的错误吗?
答案 0 :(得分:0)
我想出了如何使它工作的方法,尽管感觉它更像是一种变通方法,而不是正确的答案。
如果我从MainViewModel
构造函数中删除了以下两行:
WidgetView.SortDescriptions.Add(new SortDescription("Rank", ListSortDirection.Ascending));
WidgetView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
然后将SortDescriptions
添加到MainWindow.xaml.cs的单击处理程序中,然后得到预期的行为。现在,我的点击处理程序方法如下:
private void newViewModelButton_Click(object sender, RoutedEventArgs e)
{
var mvm = new MainViewModel();
DataContext = mvm;
mvm.WidgetView.SortDescriptions.Add(new SortDescription("Rank", ListSortDirection.Ascending));
mvm.WidgetView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
}
由于某种原因,它可以在首次点击和随后的所有点击中使用;该表会按预期更新,并且在我相应地修改Rank
和/或Name
时顺序会发生变化。我仍然不明白为什么它第一次起作用,但是如果在构造函数中更新了SortDescriptions
,则在随后的单击之后失败了。
我的理论是,DataGrid
中可能存在某种绑定,如果SortDescriptions
集合发生更改,将触发该绑定,并且该触发会导致排序工作。因此,如果SortDescriptions
在设置{{1}之后没有改变,那么DataContext
就会以某种方式错过应该进行排序的事实。为了验证该理论,我将代码改回为在构造函数中添加DataGridView
,然后在{{1之后,在单击处理程序中基于不存在的属性“ Foo”添加了新的SortDescriptions
}}分配。此还解决了该问题(尽管这不是我建议的最终解决方法)。