Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGrid filtered items, jumpy scrollbar

I have a DataGrid with an ItemSource populating the control. I also use a filter/query mechanism which filters the content of the control.

When the datagrid is not filtered, scrolling works fine. But when I filtered (=set visibility to items to false, which collapses the item in the datagrid) the scrolling becomes very 'jumpy'. When I scroll down, the scrollbar becomes larger and smaller, and scrolling becomes an annoying experience.

I read something about virtualization, and something about settings the DataGrid.ScrollViewer, but I have neither of those properties available in XAML.

Why is something which feels trivial so overly complicated... Anyway, how can I configure my datagrid to:

  • show the list of items via data binding
  • being able to filter the list (by collapsing items)
  • and obviously having a scrollbar which allows users to scroll without getting frustrated :)

My XAML:

<DataGrid Grid.Row="2"
          ItemsSource="{Binding ErrorsThatStoppedMachine}"
          AutoGenerateColumns="False"
          SelectedItem="{Binding SelectedError}"
          IsReadOnly="True"
          SelectionMode="Single">

    <DataGrid.Columns>
        <DataGridTextColumn Header="Timestamp" Width="220" Binding="{Binding Path=Timestamp}" />
        <DataGridTextColumn Header="ErrorCode" Width="90" Binding="{Binding Path=ErrorCode}" />
        <DataGridTextColumn Header="Unit" Width="70" Binding="{Binding Path=Unit}" />
        <DataGridTextColumn Header="State" Width="100" Binding="{Binding Path=MachineState}" />
        <DataGridTextColumn Header="Message" Width="*" Binding="{Binding Path=Message}" />
    </DataGrid.Columns>

    <DataGrid.RowStyle>
        <Style TargetType="{x:Type DataGridRow}"
               d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type=viewModels:ErrorViewModel}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsVisible}" Value="false">
                    <Setter Property="Visibility" Value="Collapsed" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

Many many thanks in advance.

PS: some additional explanation would be greatly appreciated, would be a nice bonus to actually learn something from this...

like image 693
bas Avatar asked Jan 05 '16 19:01

bas


1 Answers

The DataGrid has a ViewPort and will only render and calculate things that are actually shown. This is know as virtualization. Visual changes depending on Row/Cell Data will inevitably cause 'jumping', since the DataGrid will calculate them on the spot.

Settings on the Scrollviewer, as well as putting the Grid inside a Scrollviewer, will disable virtualization. This means the whole grid will be rendered at once:

  • The Grid can scroll smoothly
  • The initial load time for the Grid will be higher: to an extend it will become unusable, when too much data is attached to the grid.

If your Grid will only contain a limited amount of rows, this might be ok.


A much better approach to this problem would be to filter directly on the ItemsSource. Use a ObservableCollection and filter your data there. The Grid will display the rows accordently to the ObservableCollection.

This is exaclty the behavior you rebuilt with this RowStyle that sets Visibility.

like image 139
jHilscher Avatar answered Oct 13 '22 07:10

jHilscher