it-swarm.com.ru

WPF ListView с горизонтальным расположением элементов?

Я хочу выложить элементы в ListView аналогично WinForms ListView в режиме списка. То есть элементы располагаются не только вертикально, но и горизонтально в ListView.

Я не против, если элементы выложены так:

1 4 7
2 5 8
3 6 9

Или вот так:

1 2 3
4 5 6
7 8 9

Пока они представлены как вертикально, так и горизонтально, чтобы максимально использовать доступное пространство.

Самый близкий, который я мог найти, был этот вопрос:

Как заставить элементы WPF ListView повторяться горизонтально, как горизонтальная полоса прокрутки?

Который только выкладывает предметы только по горизонтали.

54
Grokys

Звучит так, как будто вы ищете --- WrapPannel , который будет располагать элементы горизонтально, пока не останется свободного места, а затем перейдет к следующей строке, например так:

( MSDN )
альтернативный текст http://i.msdn.Microsoft.com/Cc295081.b1c415fb-9a32-4a18-aa0b-308fca994ac9(en-us,Expression.10).png

Вы также можете использовать niformGrid , который будет размещать элементы в заданном количестве строк или столбцов.

Способ, которым мы получаем элементы для размещения с использованием этих других панелей в ListView, ListBox или любой форме ItemsControl, заключается в изменении свойства ItemsPanel . Установив ItemsPanel, вы можете изменить его со стандартной StackPanel, которая используется ItemsControls. С WrapPanel мы также должны установить ширину как показано здесь .

<ListView>
   <ListView.ItemsPanel>
      <ItemsPanelTemplate>
         <WrapPanel Width="{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>
100
rmoore

Недавно я исследовал, как добиться этого в WPF, и нашел хорошее решение. То, что я хотел, было в режиме репликации списка в проводнике Windows, то есть сверху вниз, затем слева направо.

В основном то, что вы хотите сделать, переопределяет свойство ListBox.ItemsPanel, чтобы использовать WrapPanel с его ориентацией, установленной на Вертикаль.

<ListBox>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>      
      <WrapPanel Orientation="Vertical"/>
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</ListBox>

Однако это БУДЕТ медленным при загрузке большого набора данных, так как панель переноса не виртуализирована. Это важно. Таким образом, теперь эта задача становится немного более сложной, поскольку теперь вам нужно написать собственный VirtualizedWrapPanel, расширив VirtualizedPanel и внедрив IScrollInfo.

public class VirtualizedWrapPanel : VirtualizedPanel, IScrollInfo
{
   // ...
}

Это то, что я получил в своем исследовании, прежде чем перейти к другому заданию. Если вам нужна дополнительная информация или примеры, пожалуйста, прокомментируйте.

ОБНОВИТЬ. У Бена Констебля есть замечательный серия о том, как реализовать IScrollInfo .

Всего 4 статьи. Действительно хорошее чтение.

С тех пор я реализовал виртуализированную панель переноса, это не простая задача даже с помощью серии статей выше.

21
Dennis

В моем случае лучшим вариантом было использовать:

        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Vertical"
                    MaxHeight="{Binding (FrameworkElement.ActualHeight), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
                               ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
                               MinHeight="{Binding ItemHeight, RelativeSource={RelativeSource Self}}"
                               ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>

Это дало мне достойный аналог опции списка Windows Explorer

8
Arsen Zahray

В дополнение к ответу @ Dennis о потере виртуализации WrapPanel я нашел класс Nice, который правильно реализует это. Хотя предложенный пост Бена Констебля ( Часть 1 , Часть 2 , Часть , Часть 4 ) является Хорошее введение, я не мог полностью выполнить задачу для Wrap Panel.

Вот реализация: https://virtualwrappanel.codeplex.com/ Я протестировал его с общим количеством 3.300 видео и фото, загрузка самого списка, конечно, немного длинная, но в конечном итоге это правильно виртуализировать список, никакой задержки прокрутки.

  • В этом коде есть некоторые проблемы, см. Вкладку проблем на странице выше.

После добавления исходного кода в ваш проект, пример исходного кода:

   <!--in your <Window> or <UserControl> tag -->
  <UserControl
        xmlns:hw="clr-namespace:Project.Namespace.ToClassFile" >
   <!--...-->

    <ListView x:Name="lvImages" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Margin="10" Height="auto" 
             ItemsSource="{Binding ListImages}"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <hw:VirtualizingWrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Vertical" Margin="5" MaxHeight="150">
                    <TextBlock Text="{Binding title}" FontWeight="Bold"/>
                    <Image Source="{Binding path, IsAsync=True}" Height="100"/>
                    <TextBlock Text="{Binding createDate, StringFormat=dd-MM-yyyy}"/>

                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

Бэкэнд в стиле MVVM, так что это внутри ViewModel:

    public ObservableCollection<Media> ListImages
    {
        get
        {
            return listImages;
        }
        set { listImages = value; OnPropertyChanged(); }
    }


     //Just load the images however you do it, then assign it to above list.
//Below is the class defined that I have used.
public class Media
{
    private static int nextMediaId = 1;
    public int mediaId { get; }
    public string title { get; set; }
    public string path { get; set; }
    public DateTime createDate { get; set; }
    public bool isSelected { get; set; }

    public Media()
    {
        mediaId = nextMediaId;
        nextMediaId++;
    }
}
2
CularBytes

для использования слева направо, затем сверху вниз

      <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" 
                     MaxWidth="{Binding ActualWidth, Mode=OneWay, 
                       RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type er:MainWindow}}}"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
2
kns98