5

I have a ListView in my window. The ListView's default ItemsPanel was replaced with WrapPanel. I also have a DataTemplate for it's ListViewItems. In Runtime, main window will not responding for some time because the ListView have more than 700 (and keep increasing) ListViewItems (from data binding). Is there a way to keep the main window responsive?

OPTIONAL: When the ListView is not ready, i want a text (or ProgressBar if possible) show up over the ListView and saying something like "Please Wait..." or maybe "Loading Items...".

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>

EDIT:

I tried this:

List<something> MyList = new List<something>(); 

ThreadPool.QueueUserWorkItem(_ =>
      {

          ( Create MyList here...)

          Dispatcher.BeginInvoke(new Action(() =>
          {
              MyListView.ItemsSource = MyList;
          }));
      });

Main window is still not responding until the ListView ready.

Wahyu
  • 4,203
  • 1
  • 19
  • 21
  • Is your ListView using Virtualization? I suspect it isn't since you've replaced the default ItemsPanel with a WrapPanel. Virtualization is the process that only renders the visible items, plus a few extra for a scroll buffer, and then when you scroll it replaces the DataContext behind each item. It's great for optimizing performance of large data sets. [This answer](http://stackoverflow.com/a/2784220/302677) shows how to implement it, however if your items are all of a variable size than it may not work. Also, if they're a fixed size, I'd suggest switching to a StackPanel. – Rachel Sep 22 '15 at 15:49
  • @Rachel Thats my XAML, is there anything wrong? Also my items are large data sets. – Wahyu Sep 22 '15 at 15:59
  • 1
    The problem is you're overwriting the ItemsPanelTemplate with a WrapPanel, which replaces the existing ItemsPanelTemplate which includes virtualization. Try implementing the code from [this answer](http://stackoverflow.com/a/2784220/302677) to make your new ItemsPanelTemplate virtualized. I'm not positive if the default WrapPanel can use virtualization though, but if not then I know you can google for "wpf virtualized wrappanel" and get a bunch of suggestions. – Rachel Sep 22 '15 at 16:21
  • @Rachel Yup, WrapPanel doesn't support virtualizing. I will try google it for now. Btw thx for helping :) – Wahyu Sep 22 '15 at 16:50

3 Answers3

5

You use panel (WrapPanel) which cannot do UI virtualization (unlike VirtualizingStackPanel which is used in default ListView ItemPanel template). What that means is all your items are rendered, even those which are not visible at the moment. WPF does not have virtualizing wrap panel built-in, as far as I know, so you can try some free virtualizing wrap panels (example - http://virtualwrappanel.codeplex.com/), but I cannot say how good they are, I use version from Telerik which is not free. Another option is switch back to VirtualizingStackPanel. In addition to that, ensure that you load your items on non-UI thread (as mentioned in another answer).

Evk
  • 98,527
  • 8
  • 141
  • 191
  • I changed the `ItemsPanel` template to its default. You right, it is better now, it loads a lot faster than before! but since its a `StackPanel`, my `ListView` has many empty space now. My `ListViewItem`s's sizes are fixed, it is 213x336 (`ListView`'s size: 577x902). Do you any idea so i can fill the empty space? – Wahyu Sep 22 '15 at 16:27
  • @Wahyu Well if wrap panel is natural fit for you, try that free VirtualWrapPanel mentioned in my answer. Also try this - http://www.codeproject.com/Articles/75847/Virtualizing-WrapPanel. – Evk Sep 22 '15 at 16:33
  • Ok, i will try that later because its already late night in here. Thx for helping! – Wahyu Sep 22 '15 at 16:47
3

If the UI thread is doing a Long-time operation it won't be able to process UI requests. This is also known as Not Responding. Use ThreadPool like this:

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
      }));
    });
}
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
3

After googling for some time. Thx to this article, Virtualizing WrapPanel is not impossible! Here's how:

  1. Download the code from here
  2. Add it to your project (In VS2010: Project > Add Existing Item)
  3. Add the namespace to your XAML:

    xmlns:mwc="clr-namespace:MyWinCollection"
    
  4. Use VirtualizingWrapPanel as your ListView's ItemsTemplate:

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

Done!

Since not all items are rendered at once, the main window is fully responsive now.

Hopes this help! :D

Btw, thx guys! You guys saved my day.

Wahyu
  • 4,203
  • 1
  • 19
  • 21