Виртуализация WrapPanel в виде ListT-ов ItemsTemplate

У меня есть ListView в моем окне. ListViewпо умолчанию ItemsPanel был заменен на WrapPanel, у меня тоже есть DataTemplate ибо это ListViewItems. Во время выполнения главное окно не будет отвечать в течение некоторого времени, потому что ListView иметь более 700 (и продолжать расти) ListViewItems (из привязки данных). Есть ли способ сохранить отзывчивость главного окна?

ДОПОЛНИТЕЛЬНО: когда 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 не будет готов.

3 ответа

Решение

После поиска в Google в течение некоторого времени. Спасибо этой статье, Виртуализация WrapPanel не является невозможной! Вот как:

  1. Загрузите код отсюда
  2. Добавьте его в свой проект (В VS2010: Проект> Добавить существующий элемент)
  3. Добавьте пространство имен в свой XAML:

    xmlns:mwc="clr-namespace:MyWinCollection"
    
  4. использование VirtualizingWrapPanel как твой ListView"s ItemsTemplate:

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

Готово!

Поскольку не все элементы отображаются одновременно, главное окно теперь полностью адаптивно.

Надеется, что это поможет!: D

Кстати, спасибо, ребята! Вы, ребята, спасли мой день.

Вы используете панель (WrapPanel), которая не может выполнять виртуализацию пользовательского интерфейса (в отличие от VirtualizingStackPanel, который используется в шаблоне ListView ItemPanel по умолчанию). Это означает, что все ваши элементы отображаются, даже те, которые не видны в данный момент. Насколько я знаю, в WPF нет встроенной панели виртуализации, поэтому вы можете попробовать несколько бесплатных панелей виртуализации (пример - http://virtualwrappanel.codeplex.com/), но я не могу сказать, насколько они хороши, Я использую версию от Telerik, которая не является бесплатной. Другой вариант - переключиться обратно на VirtualizingStackPanel. В дополнение к этому, убедитесь, что вы загружаете свои элементы в не-пользовательский интерфейс (как упоминалось в другом ответе).

Если поток пользовательского интерфейса выполняет долгую операцию, он не сможет обрабатывать запросы пользовательского интерфейса. Это также известно как не отвечает. использование 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
      }));
    });
}
Другие вопросы по тегам