Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtualizing WrapPanel as ListView's ItemsTemplate

Tags:

c#

listview

wpf

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.

like image 467
Wahyu Avatar asked Sep 22 '15 15:09

Wahyu


2 Answers

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).

like image 70
Evk Avatar answered Sep 24 '22 01:09

Evk


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
      }));
    });
}
like image 28
Salah Akbari Avatar answered Sep 24 '22 01:09

Salah Akbari