I have a UserControl
with the following Xaml representing a simple DataGrid
with buttons for testing:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid x:Name="TestGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="Init View" Click="InitViewButton_Click"/>
<Button Content="Add" Click="AddButton_Click"/>
<Button Content="Change Ids" Click="ChangeIdButton_Click"/>
<Button Content="Filter X" Click="FilterButton_Click"/>
</StackPanel>
</Grid>
And (in code-behind) following code:
public ListCollectionView TestView {get; set;}
public ObservableCollection<TestItem> TestItems {get; set;}
private void init()
{
var result = new ObservableCollection<TestItem>()
{
new TestItem() { Id = 1, Name = "First A" },
new TestItem() { Id = 2, Name = "Second A" },
new TestItem() { Id = 3, Name = "Third A" },
};
TestItems = result;
var view = new ListCollectionView(TestItems);
view.SortDescriptions.Add(new SortDescription(nameof(TestItem.Id), ListSortDirection.Descending));
view.IsLiveSorting = true;
view.Filter = o => (o as TestItem)?.Name.Contains("A") ?? false;
TestView = view;
}
private void InitViewButton_Click(object sender, RoutedEventArgs e)
{
init();
TestGrid.ItemsSource = TestView;
TestGrid.Items.Refresh();
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
var item = new TestItem() { Id = 99, Name = "New AX" };
TestItems.Add(item);
}
private void ChangeIdButton_Click(object sender, RoutedEventArgs e)
{
foreach (var testItem in TestItems)
{
testItem.Id = Random.Shared.Next(1000);
}
}
private void FilterButton_Click(object sender, RoutedEventArgs e)
{
TestView.Filter = o => (o as TestItem)?.Name.Contains("X") ?? false;
}
After clicking on "Init View" the DataGrid
is populated as expected and the other buttons work as expected, e.g. when changing the Ids the rows are resorted.
If I then click on "Init View" again, everything is ok, except for re-sorting, i.e. changing the Ids does not resort the rows - the displayed items are updated correctly, though.
How can this be?
Side note: despite not having set IsLiveFiltering
, filtering works as expected, e.g. if I remove the "A" from a Name the item is removed from the DataGrid
.
It looks like somehow the SortDescriptions
are being cleared after setting the DataGrid ItemsSource
to the new ListCollectionView
(after the first time).
If you add the SortDescription
after TestGrid.ItemsSource = TestView
, it works:
private void init()
{
var result = new ObservableCollection<TestItem>()
{
new TestItem() { Id = 1, Name = "First A" },
new TestItem() { Id = 2, Name = "Second A" },
new TestItem() { Id = 3, Name = "Third A" },
};
TestItems = result;
var view = new ListCollectionView(TestItems);
view.IsLiveSorting = true;
view.Filter = o => (o as TestItem)?.Name.Contains("A") ?? false;
TestView = view;
}
private void InitViewButton_Click(object sender, RoutedEventArgs e)
{
init();
TestGrid.ItemsSource = TestView;
TestView.SortDescriptions.Add(new SortDescription(nameof(TestItem.Id), ListSortDirection.Descending));
//TestGrid.Items.Refresh();
}