使用ListViews与WPF中的嵌套对象的可怕性能

时间:2011-01-12 09:51:07

标签: wpf performance data-binding listview

就像在标题中提到的那样,如果我将ListView用于嵌套对象,我会得到一个糟糕的表现。 我的情况是: ListView的每一行都显示类Transaction的对象,其中包含以下属性:

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;

每个属性都可以通过其相应的属性访问。 ObservableCollection<Transaction>绑定到ItemsSource的{​​{1}}。 ListView本身如下所示:

ListView

正如您在 screenshot 中所看到的,用户可以使用组合框更改事务属性的值。

现在好了我的问题。如果我点击“Laden”按钮,应用程序将在 </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> 中加载大约150个条目。在我填写集合之前,我将ObservableCollection<Transaction>的{​​{1}}设置为ItemsSource,填写后我再次将集合绑定到ListView。加载本身需要几毫秒,但填充集合的渲染需要很长时间(150个条目=约20秒)。我测试了删除xaml中的所有null并获得了更好的性能,因为我不必为每一行填充ItemsSource。但我需要使用这些组合框来修改Comboboxes的属性。

有人知道如何改善表现吗?

THX

4 个答案:

答案 0 :(得分:3)

到目前为止,所有答案似乎都集中在使UI更快地执行,而在我看来,数据收集应该归咎于此。我做了类似的应用程序,没有性能问题。绑定的属性是否表示字段或查询?

答案 1 :(得分:0)

150个条目对我来说听起来不多,20秒听起来好像很长时间。在你发布的内容中我看不到任何不妥之处,但这并不意味着那里没有问题。

首先要看的是查看UI Virtualization是否已启用。

Potentailly尝试查看DataGrid而不是ListView是否提高了性能(与wpf4捆绑在一起,还是可以作为WPFToolKit的一部分下载)?

提高整体性能还有一件事(但如果您的UI已经在使用UI虚拟化,可能无法修复初始问题)将是实现Data Virtualization。它看起来很棘手,但文章非常擅长引导您完成它,它是提高渲染大型数据列表性能的最佳解决方案。

作为最后一个解决方法,您可以考虑使用某种分页机制,这样您在任何时候都只能显示较少数量的项目。您可以查看具有页码,前进,后退按钮的经典分页解决方案。

答案 2 :(得分:0)

我们可以看一下你的数据结构的更大图片吗?我担心的是一些组合框正在获取他们的数据。例如,

<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}">

这取决于事务集合中每个对象的发件人列表是否不同。如果没有,我建议将发件人列表/集合加载到xaml中自己的资源中,然后将值从那里拉到组合框中。就像现在一样,每个组合框必须查询它的相应对象获取列表,然后预渲染该列表。 4个组合框乘以150个对象是600个数据列表,以便彼此分开获取和预渲染。

如果您将这些列表提取到XAML资源中,则只能存储4个列表。

修改

也只是出于好奇,它是一个设计要求(例如客户希望它看起来如此)同时显示控件和编辑控件?您可以改为使用一个模板进行显示而另一个模板进行编辑,这样当未选择记录时,所有单元格都是TextBlocks,当选择记录时,单元格是编辑控件,ComboBox,TextBox,DatePicker等。

答案 3 :(得分:0)

我有同样的问题,最后发现它是由于与ListView或ComboBox无关的东西。

恰好ListView嵌套在Infragistic TabControl中,并且每次在ListView中绑定某些内容(即:ComboBoxes)时,TabControl的“SelectionChange”都会被触发,导致延迟......

我还使用原生的Microsft TabControl进行了测试,但我得到了相同的行为,但性能稍微高一些。

我通过验证SelectionChangedEventArgs解决了这个问题...确保e.AddedItems在处理之前只包含“TabItem”(而不是ComboBox)。

希望它有所帮助,