Search code examples
c#wpfdevexpress

Performance issue with a DataGridComboboxColumn


I am new to WPF and devexpress and I am currently re-implementing an application. My goal is to delete all references to devexpress in a WPF application and replace it using WPF only.

Now I have this DataGridComboBoxColumn whose purpose is to bind an employee to a post (e.g. Project Manager). In this combobox there are about 3000 items. When the application was using the GridControl there were no performance issue (no slowing during UI rendering). It was simply using a GridControl and a ComboBoxEdit as a controltemplate of one of the columns.

In WPF I have replaced this by:

`<DataGrid x:Name="gridProject" AutoGenerateColumns="False" CanUserAddRows="True"
      ItemsSource="{Binding Source={StaticResource ProjectCollectionView}}"
      SelectionMode="Single"
      EnableRowVirtualization="True"
      EnableColumnVirtualization="True"
      VirtualizingStackPanel.IsVirtualizing="True"
      VirtualizingStackPanel.VirtualizationMode="Recycling"
      RowHeight="25">


<!-- How to display the person: "NAME FirstName" -->
<DataGrid.Resources>
    <DataTemplate x:Key="displayFullNameTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Name, Mode=OneWay, IsAsync=True}"></TextBlock>
            <TextBlock Text=" "></TextBlock>
            <TextBlock Text="{Binding FirstName, Mode=OneWay, IsAsync=True}"></TextBlock>
        </StackPanel>
    </DataTemplate>
    <ItemsPanelTemplate x:Key="virtualizeItemsPanelTemplate">
        <VirtualizingStackPanel />
    </ItemsPanelTemplate>
</DataGrid.Resources>

<DataGridComboBoxColumn Header="Chief"
                        SelectedValueBinding="{Binding ChiefReference}"
                        SelectedValuePath="Matricule"
                        Width="200">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Source={StaticResource usersList}, Path=Users, IsAsync=True}"/>
            <Setter Property="ItemTemplate" Value="{StaticResource displayFullNameTemplate}"/>
            <Setter Property="ItemsPanel" Value="{StaticResource virtualizeItemsPanelTemplate}"/>
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Source={StaticResource usersList}, Path=Users, IsAsync=True}"/>
            <Setter Property="ItemTemplate" Value="{StaticResource displayFullNameTemplate}"/>
            <Setter Property="ItemsPanel" Value="{StaticResource virtualizeItemsPanelTemplate}"/>
            <Setter Property="IsEditable" Value="True"/>
            <Setter Property="IsTextSearchEnabled" Value="True"/>
            <Setter Property="TextSearch.TextPath" Value="Name"/>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>`

I had to display all names as "Name FirstName" and a user had to be able to search in the combobxes using a name. I had sereval issues that I managed to solve thanks to Google: - Imposing a row height and a columne width - Asynchronous loading to display the items when editing a combobox or when displaying the value taken by a combobox. - I virtualized the drop-down list of the combobox and the combobox textblock. - I enabled both row and column virtualization.

The exact issue is the following: when navigating in the datagrid, when scrolling, if the DataGridComboBoxColumn is in the view then the scrolling becomes slow. Then if I scroll back to a view where this column isn't visible and it is fluent again. And then if I go back on this column, the application takes some times (like 3 seconds) to display the contents of the comboboxes.

There are about 10 columns and 30 rows by view in the application.

So I think the issue is linked to the fact that the application has to display 30 items and for each items it has to do the binding and apply the template to display the information as I asked. What bothers me is the fact that using devexpress there is absolutely no performance issue.

Am I doing something wrong? Am I forgetting something? Please help me :( Thanks in advance!

EDIT: I updated .NET to the 4.5.2 version. Another problem appeared after doing this: since I was spamming IsAsync I had to use a delegate to fill my static resource (the "user list"). So now the application takes some time at the begining to load this resource (that I create by hand). The issue still remains though.


Solution

  • I have found a solution which is not a direct one.

    Instead of trying to improve the grid performances I directly changed my database. I have added a calculated column to my project database which is a string "NAME FirstName".

    So in my datagrid, instead of displaying the selected value in the elementstyle of the combobox, I display a scalar value. Hence nothing to search in the huge list at display time.

    Something like this:

    <DataGridComboBoxColumn Header="Chief"
                            Width="200">
        <DataGridComboBoxColumn.ElementStyle>
            <Style TargetType="{x:Type ComboBox}">
                <Setter Property="ItemsSource" Value="{Binding ProjectCollectionView}"/>
                <Setter Property="SelectedValue" Value="{Binding ChiefReference, Mode=OneWay}"/>
                <Setter Property="SelectedValuePath" Value="ChiefReference"/>
                <Setter Property="ItemTemplate" Value="{StaticResource displayFullNameTemplateElement}"/>
                <Setter Property="ItemsPanel" Value="{StaticResource virtualizeItemsPanelTemplate}"/>
                <Setter Property="IsSynchronizedWithCurrentItem" Value="False"/>
            </Style>
        </DataGridComboBoxColumn.ElementStyle>
        <DataGridComboBoxColumn.EditingElementStyle>
            <Style TargetType="{x:Type ComboBox}">
                <Setter Property="ItemsSource" Value="{Binding usersList IsAsync=True}"/>
                <Setter Property="ItemTemplate" Value="{StaticResource displayFullNameTemplate}"/>
                <Setter Property="ItemsPanel" Value="{StaticResource virtualizeItemsPanelTemplate}"/>
                <Setter Property="IsEditable" Value="True"/>
                <Setter Property="IsTextSearchEnabled" Value="True"/>
                <Setter Property="TextSearch.TextPath" Value="Name"/>
                <Setter Property="SelectedValue" Value="{Binding ChiefReference}"/>
                <Setter Property="SelectedValuePath" Value="ChiefReferenceOfTheUserList"/>
                <Setter Property="IsSynchronizedWithCurrentItem" Value="False"/>
            </Style>
        </DataGridComboBoxColumn.EditingElementStyle>
    </DataGridComboBoxColumn>
    

    Now the issue is that since the elementstyle is bound to a property and the editing style to another, a change of the selectedvalue of the combobox doesn't change the displayed value of the datagrid. This is because I don't save changes dynamically, the user has to press a "save" button to save changes. Thus these changes are visible only after saving changes which is a bit annoying. But it's another issue and at least performances are good now.