Подтвердить что ты не робот

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 повторяющимися по горизонтали, например, горизонтальной полосой прокрутки?

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

4b9b3361

Ответ 1

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

(MSDN)
alt text http://i.msdn.microsoft.com/Cc295081.b1c415fb-9a32-4a18-aa0b-308fca994ac9(en-us,Expression.10).png

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

То, как мы получаем элементы для аргезии с использованием этих других панелей в 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>

Ответ 2

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

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

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

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

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

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

UPDATE. Бен Констебль имеет отличную серию о том, как реализовать IScrollInfo.

Всего 4 статьи. Очень хорошо читать.

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

Ответ 3

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

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

Ответ 4

слева направо, а сверху вниз -

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

Ответ 5

В дополнение к ответу @Dennis, о WrapPanel, теряющем виртуализацию, я нашел хороший класс, который правильно реализует это. В то время как предложенная должность Бена Констебля (часть 1, Часть 2, часть 3, часть 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++;
    }
}