【发布时间】:2018-08-13 19:28:48
【问题描述】:
我有一个类“Widget”的集合,它具有 Name(字符串)和 Rank(int)属性。我在我的视图模型中创建了一个 CollectionViewSource 实例,该实例按 Rank 然后按名称声明排序顺序。在我的视图模型构造函数中,我创建了三个小部件,其中 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 |
如果我编辑排名值,行将相应移动。例如,如果我将 W_2 的 Rank 设置为 10,它将移动到 W_1 以下。如果我将所有 Rank 值设置为相等,然后更改名称,则表格将按预期按新名称的字母顺序排序。
但是,如果我再次单击该按钮,表格现在将按名称排序。
| Name | Rank |
|------|------|
| W_1 | 3 |
| W_2 | 2 |
| W_3 | 1 |
并且更改排名或名称值没有效果。就好像所有的排序逻辑都被清除了,实时排序根本不再发生。
为什么当 DataContext 发生变化时行为会有所不同?
更新: 我将 DataGrid 替换为具有类似功能的 ItemsControl(名称和排名的 TextBox),它继续按照我的预期使用 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 控件的情况会再次中断。这可能是一个实际的错误吗?
【问题讨论】:
标签: c# wpf datagrid collectionviewsource