WPF - Binding large amount of data in Listbox
I am creating a search page for books. There is lots of data in the database. If the data size is more than 2000 the application hangs. ItemsSource of the listbox having the data but something wrong is happening behind.
Code
<ListBox Grid.Column="1"
x:Name="lbResult"
ItemsSource="{Binding}"
SelectionChanged="lbResult_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Width="320">
<TextBlock Margin="10">
开发者_运维知识库 <InlineUIContainer>
<TextBlock Foreground="DarkKhaki" Text="{Binding Title}"/>
</InlineUIContainer>
<Run Text=" "/><LineBreak/>
<InlineUIContainer>
<TextBlock Text=" By "/>
</InlineUIContainer>
<Run Text=" "/>
<InlineUIContainer>
<TextBlock Text="{Binding Author}"/>
</InlineUIContainer>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
The application is apparently "hanging" because the data load is happening on the UI thread.
You should consider a different model that enables you to load the data in another thread and update the UI periodically or as and when new data arrives.
You can use an ObservableCollection
for this.
The background loading thread updates the collection and this fires an event out to the UI thread indicating that an update is required.
There's an example of how to do this on GALA Soft
You create a property (read only in this case) for the collection:
private ObservableCollection<MyDataItem> dataItems;
public ObservableCollection<MyDataItem> DataItems
{
get { return dataItems; }
}
Then in your XAML:
<ListBox ItemsSource="{Binding ElementName=mainWindow, Path=DataItems}"
...>
</ListBox>
One problem that you may have is that you are using a non-virtualizing type of panel (WrapPanel) in your ItemsPanelTemplate. What this means is that all 2000 data items will be loaded even if only a fraction of those are visible. By default ListBox uses a VirtualizingStackPanel as its panel which, as the name indicates, provides virtualisation, so it will only load the visible data set elements.
So an easy fix in terms of performance would be to dispense with the WrapPanel and us a virtualizing panel instead, however this would obviously change the appearance.
If you particularly want a WrapPanel then there is no virtualised equivalent provided by WPF, but there are implementations out there, such as http://virtualwrappanel.codeplex.com/.
Try using a ListView instead, I had the same problem. Now I can load over 7000 items in an instant.
Like this:
<StackPanel Grid.Row="1" Grid.Column="0">
<ListView
Height="100"
Name="lstPlayerList">
<ListView.View>
<GridView>
<GridViewColumn
Width="100"
Header="LastName"
DisplayMemberBinding="{Binding LastName}">
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
精彩评论