我正在创建一个书籍的搜索页面。数据库中有很多数据。如果数据大小超过2000,应用程序就会挂起。列表框的ItemsSource有数据,但后面发生了一些问题。
编码
<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>
应用程序显然是 "挂起 "的,因为数据加载发生在UI线程上。
你应该考虑一种不同的模式,使你能够在另一个线程中加载数据,并定期或在新数据到达时更新UI。
您可以使用一个 ObservableCollection
的事件。
后台加载线程更新集合,并向UI线程发出一个事件,表示需要更新。
这里有一个例子来说明如何在 GALA软体
您为该集合创建一个属性(在本例中为只读)。
private ObservableCollection<MyDataItem> dataItems;
public ObservableCollection<MyDataItem> DataItems
{
get { return dataItems; }
}
然后在你的XAML中,
<ListBox ItemsSource="{Binding ElementName=mainWindow, Path=DataItems}"
...>
</ListBox>
你可能会有一个问题,那就是你在ItemsPanelTemplate中使用了一个非虚拟化类型的面板(WrapPanel)。这意味着所有的2000个数据项将被加载,即使其中只有一小部分是可见的。默认情况下,ListBox使用VirtualizingStackPanel作为它的面板,正如其名称所示,它提供了虚拟化,所以它将只加载可见的数据集元素。
因此,在性能方面,一个简单的修复方法就是放弃WrapPanel,而使用一个虚拟化的面板,然而这显然会改变外观。
如果你特别想要一个WrapPanel,那么WPF并没有提供虚拟化的等价物,但是有一些实现,例如 http:/virtualwrappanel.codeplex.com。.
试着用ListView代替,我也有同样的问题。 现在我可以瞬间加载超过7000个项目。
就像这样。
<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>