Search code examples
wpfdatagridtabcontrolcollectionviewsource

CollectionViewSource doesn't sort after selecting new tab on TabControl


I am sorting a datagrid within a UserControl that is displayed inside of a TabControl.

The main window contains the TabControl as shown here.

<Grid>
    <TabControl x:Name="EquipTabs" ItemsSource="{Binding Equipment}" >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ctrls:MachData DataContext="{Binding Path=MachineViewModel}" />
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

The user control sorts the datagrid correctly when the first tab is activated. However, when I click on a different tab or switch back to the original one, the datagrid doesn't sort.

<UserControl.Resources>
    <CollectionViewSource x:Key="StatesSource" Source="{Binding States}" >
        <CollectionViewSource.SortDescriptions>
            <scm:SortDescription PropertyName="StartTime" Direction="Descending" />
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
</UserControl.Resources>

<Grid>
    <DataGrid x:Name="dgStates" Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
              ItemsSource="{Binding Source={StaticResource StatesSource}}">
    </DataGrid>
</Grid>

The trace for the binding shows the following:

    Deactivate
    Replace item at level 0 with {NullDataItem}
    Activate with root item MachDataViewModel (hash=25379957)
    At level 0 using cached accessor for MachDataViewModel.States: RuntimePropertyInfo(States)

Why does the sort only occur initially?

Thanks for any help.


Solution

  • This happens because of the way DataGrid works. DataGrid clears SortDescriptions before setting ItemsSource.

    If we can apply our SortDescriptions after DataGrid is finished with ItemsSource, our SortDescriptions will work.

    TargetUpdated event comes to rescue, but to use it we have to set NotifyOnTargetUpdated=True in our Binding.

    <DataGrid 
       TargetUpdated="dgStates_TargetUpdated"
       ItemsSource="{Binding Source={StaticResource StatesSource}, NotifyOnTargetUpdated=True}" />
    

    Code :

    private void dgStates_TargetUpdated(object sender, DataTransferEventArgs e)
    {
        CollectionViewSource sc = this.Resources["StatesSource"] as CollectionViewSource;
        sc.SortDescriptions.Add(new System.ComponentModel.SortDescription("Name", System.ComponentModel.ListSortDirection.Ascending));
    }