将WrapPanel虚拟化为ListView's ItemsTemplate

本文关键字:ItemsTemplate ListView WrapPanel 虚拟化 | 更新日期: 2023-09-27 18:14:02

我有一个ListView在我的窗口。将ListView的默认ItemsPanel替换为WrapPanel。我还有一个DataTemplate,因为它是ListViewItem s。在运行时,主窗口将不响应一段时间,因为ListView有超过700(并不断增加)ListViewItem s(从数据绑定)。是否有办法保持主窗口响应?

可选:当ListView还没有准备好,我想要一个文本(或ProgressBar如果可能的话)显示在ListView上,说一些像"请等待…"或"加载项目…"。

XAML:

 <ListView x:Name="MyListView" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" HorizontalAlignment="Left"  Height="577" VerticalAlignment="Top" Width="902" ScrollViewer.HorizontalScrollBarVisibility="Auto" Foreground="Black" Margin="10,10,0,0" ScrollViewer.CanContentScroll="True" BorderBrush="#FFC54B4B" BorderThickness="3" Background="White">
                    <ListView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapPanel MaxWidth="{Binding (FrameworkElement.ActualWidth), 
                                RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
                                ItemWidth="{Binding (ListView.View).ItemWidth, 
                                RelativeSource={RelativeSource AncestorType=ListView}}"
                                MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
                                ItemHeight="{Binding (ListView.View).ItemHeight, 
                                RelativeSource={RelativeSource AncestorType=ListView}}" />
                        </ItemsPanelTemplate>
                    </ListView.ItemsPanel>
</ListView>
编辑:

我试过了:

List<something> MyList = new List<something>(); 
ThreadPool.QueueUserWorkItem(_ =>
      {
          ( Create MyList here...)
          Dispatcher.BeginInvoke(new Action(() =>
          {
              MyListView.ItemsSource = MyList;
          }));
      });

主窗口仍然没有响应,直到ListView准备好。

将WrapPanel虚拟化为ListView's ItemsTemplate

你使用的面板(WrapPanel)不能做UI虚拟化(不像VirtualizingStackPanel在默认的ListView ItemPanel模板中使用)。这意味着您的所有项目都被渲染,甚至是那些目前不可见的项目。据我所知,WPF没有内置的虚拟化封装面板,因此您可以尝试一些免费的虚拟化封装面板(例如- http://virtualwrappanel.codeplex.com/),但我不能说它们有多好,我使用的是Telerik的版本,它不是免费的。另一个选择是切换回VirtualizingStackPanel。除此之外,确保在非ui线程上加载项目(如另一个答案所述)。

如果UI线程正在执行长时间操作,它将无法处理UI请求。这也被称为不回应。这样使用ThreadPool:

private void operation_Click(object sender, RoutedEventArgs e)
{
 ThreadPool.QueueUserWorkItem(_ =>
    {
      var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding
      //use the Dispatcher to "return" to the UI thread
      Dispatcher.BeginInvoke(new Action(() =>
      {
         //Use result
      }));
    });
}

在谷歌上搜索了一段时间后。多亏了这篇文章,虚拟化WrapPanel并非不可能!方法如下:

  1. 从这里下载代码
  2. 添加到您的项目(在VS2010:项目>添加现有项目)
  3. 将名称空间添加到XAML:

    xmlns:mwc="clr-namespace:MyWinCollection"
    
  4. 使用VirtualizingWrapPanel作为ListViewItemsTemplate:

    <ListView x:Name="MyListView" ItemsSource="{StaticResource ItemCollection}">
      <ListView.ItemsPanel>
         <ItemsPanelTemplate>
            <VirtualizingWrapPanel Orientation="Horizontal"/> 
         </ItemsPanelTemplate>
       </ListView.ItemsPanel> 
    </ListView>
    

完成了!

由于不是所有的项目都被一次呈现,主窗口现在是完全响应的。

希望这有帮助!: D

顺便说一句,谢谢你们!你们帮了我大忙。