Horrorble performance using ListViews with nested objects in WPF
- by Christian
Hi community,
like mentioned in the title I get a horrible performance if I use ListViews with nested objects.
My scenario is:
Each row of a ListView presents an object of the class Transaction with following attributes:
private int mTransactionID;
private IBTTransactionSender mSender;
private IBTTransactionReceiver mReceiver;
private BTSubstrate mSubstrate;
private double mAmount;
private string mDeliveryNote;
private string mNote;
private DateTime mTransactionDate;
private DateTime mCreationTimestamp;
private BTEmployee mEmployee;
private bool mImported;
private bool mDescendedFromRecurringTransaction;
Each attribute can be accessed by its corresponding property. An ObservableCollection<Transaction> is bound to the ItemsSource of a ListView. The ListView itself looks like the following:
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.ToSave" Width="80">
<GridViewColumnHeader Name="GVCHLoadedToSave" Style="{StaticResource ListViewHeaderStyle}">Speichern</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<CheckBox Name="CBListViewItem" IsChecked="{Binding Path=Transaction.ToSave, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.TransactionDate" Width="80">
<GridViewColumnHeader Name="GVCHLoadedDate" Style="{StaticResource ListViewHeaderStyle}">Datum</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding ElementName=DPDate, Path=Text}" Style="{StaticResource GridBlockStyle}"/>
<toolkit:DatePicker Name="DPDate"
Width="{Binding ElementName=GVCHDate, Path=ActualWidth}"
SelectedDateFormat="Short"
Style="{StaticResource GridEditStyle}"
SelectedDate="{Binding Path=Transaction.TransactionDate, Mode=TwoWay}"
SelectedDateChanged="DPDate_SelectedDateChanged"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Sender.Description" Width="120">
<GridViewColumnHeader Name="GVCHLoadedSender" Style="{StaticResource ListViewHeaderStyle}">Von</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Sender.Description}" Style="{StaticResource GridBlockStyle}"/>
<ComboBox Name="CBSender"
Width="{Binding ElementName=GVCHSender, Path=ActualWidth}"
SelectedItem="{Binding Path=Transaction.Sender}"
DisplayMemberPath="Description"
Text="{Binding Path=Sender.Description, Mode=OneWay}"
ItemsSource="{Binding ElementName=Transaction, Path=SenderList}"
Style="{StaticResource GridEditStyle}">
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Receiver.Description" Width="120">
<GridViewColumnHeader Name="GVCHLoadedReceiver" Style="{StaticResource ListViewHeaderStyle}">Nach</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Receiver.Description}" Style="{StaticResource GridBlockStyle}"/>
<ComboBox Name="CBReceiver"
Width="{Binding ElementName=GVCHReceiver, Path=ActualWidth}"
SelectedItem="{Binding Path=Transaction.Receiver}"
DisplayMemberPath="Description"
Text="{Binding Path=Receiver.Description, Mode=OneWay}"
ItemsSource="{Binding ElementName=Transaction, Path=ReceiverList}"
Style="{StaticResource GridEditStyle}">
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Substrate.Description" Width="140">
<GridViewColumnHeader Name="GVCHLoadedSubstrate" Style="{StaticResource ListViewHeaderStyle}">Substrat</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Substrate.Description}" Style="{StaticResource GridBlockStyle}"/>
<ComboBox Name="CBSubstrate"
Width="{Binding ElementName=GVCHSubstrate, Path=ActualWidth}"
SelectedItem="{Binding Path=Transaction.Substrate}"
DisplayMemberPath="Description"
Text="{Binding Path=Substrate.Description, Mode=OneWay}"
ItemsSource="{Binding ElementName=Transaction, Path=SubstrateList}"
Style="{StaticResource GridEditStyle}">
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Amount" Width="80">
<GridViewColumnHeader Name="GVCHLoadedAmount" Style="{StaticResource ListViewHeaderStyle}">Menge [kg]</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Amount}" Style="{StaticResource GridBlockStyle}"/>
<TextBox Name="TBAmount" Text="{Binding Path=Transaction.Amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ElementName=GVCHAmount, Path=ActualWidth}" Style="{StaticResource GridTextBoxStyle}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.DeliveryNote" Width="100">
<GridViewColumnHeader Name="GVCHLoadedDeliveryNote" Style="{StaticResource ListViewHeaderStyle}">Lieferschein Nr.</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.DeliveryNote}" Style="{StaticResource GridBlockStyle}"/>
<TextBox Name="TBDeliveryNote" Text="{Binding Path=Transaction.DeliveryNote, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ElementName=GVCHDeliveryNote, Path=ActualWidth}" Style="{StaticResource GridEditStyle}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Note" Width="190">
<GridViewColumnHeader Name="GVCHLoadedNote" Style="{StaticResource ListViewHeaderStyle}">Bemerkung</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Note}" Style="{StaticResource GridBlockStyle}"/>
<TextBox Name="TBNote" Text="{Binding Path=Transaction.Note, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ElementName=GVCHNote, Path=ActualWidth}" Style="{StaticResource GridEditStyle}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn core:SortableListView.SortPropertyName="Transaction.Employee.LastName" Width="100">
<GridViewColumnHeader Name="GVCHLoadedEmployee" Style="{StaticResource ListViewHeaderStyle}">Mitarbeiter</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Transaction.Employee.LastName}" Style="{StaticResource GridBlockStyle}"/>
<ComboBox Name="CBEmployee"
Width="{Binding ElementName=GVCHEmployee, Path=ActualWidth}"
SelectedItem="{Binding Path=Transaction.Employee}"
DisplayMemberPath="LastName"
Text="{Binding Path=Employee.LastName, Mode=OneWay}"
ItemsSource="{Binding ElementName=Transaction, Path=EmployeeList}"
Style="{StaticResource GridEditStyle}">
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
As you can see in the screenshot the user got the possibility to change the values of the transaction attributes with comboboxes.
Ok now to my problem. If I click on the "Laden" button the application will load about 150 entries in the ObservableCollection<Transaction>. Before I fill the collection I set the ItemsSource of the ListView to null and after filling I bind the collection to the ItemsSource once again. The loading itself takes a few milliseconds, but the rendering of the filled collection takes a long time (150 entries = about 20 sec). I tested to delete all Comboboxes out of the xaml and i got a better performance, because I don't have to fill the ComboBoxes for each row. But I need to have these comboboxes for modifing the attributes of the Transaction.
Does anybody know how to improve the performance?
THX