WPF ListView avec disposition horizontale des articles?

je veux présenter les éléments dans un ListView d'une manière similaire à la WinForms ListView en mode Liste. C'est, où les éléments sont disposés non seulement verticalement, mais horizontalement dans la ListView.

cela ne me dérange pas si les articles sont disposés comme ceci:

1 4 7

2 5 8

3 6 9

ou comme ceci:

1 2 3

4 5 6

7 8 9

tant Qu'ils sont présentés à la fois verticalement et horizontalement afin de maximiser l'utilisation de l'espace disponible.

la question la plus proche que j'ai pu trouver était:

Comment faire pour que les éléments ListView WPF se répètent horizontalement, comme une barre de défilement horizontale?

qui ne présente les articles qu'horizontalement.

54
demandé sur Community 2009-06-25 03:55:07

5 réponses

cela ressemble à ce que vous cherchez est un WrapPannel , qui va poser les articles horizontalement jusqu'à ce qu'il n'y ait plus de place, et puis passer à la ligne suivante, comme ceci:

( MSDN )

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

vous pouvez aussi utiliser un UniformGrid , qui placera les articles dans un nombre défini de lignes ou de colonnes.

la façon dont nous obtenons les articles à changer en utilisant ces autres panneaux dans une ListView, une ListBox, ou toute forme de ItemsControl est en changeant la propriété ItemsPanel . En paramétrant la fonction ItemsPanel, vous pouvez la modifier à partir du StackPanel par défaut utilisé par ItemsControls. Avec le WrapPanel, nous devrions également définir les largeurs comme montré ici .

<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
répondu rmoore 2016-05-04 20:20:34

j'ai récemment fait des recherches sur la façon d'atteindre cet objectif dans WPF et j'ai trouvé une bonne solution. Ce que je voulais, c'était reproduire le mode liste dans Windows Explorer, c'est-à-dire de haut en bas, puis de gauche à droite.

essentiellement ce que vous voulez faire outrepasser la propriété ListBox.ItemsPanel pour utiliser un WrapPanel avec son orientation définie à la verticale.

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

cependant ce sera lent lors du chargement d'un ensemble de données de grande taille car il le panneau enveloppant est pas virtualisé. Ce qui est important. Donc cette tâche devient maintenant un peu plus que maintenant vous avez besoin d'écrire votre propre VirtualizedWrapPanel en étendant VirtualizedPanel et en implémentant IScrollInfo.

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

voilà Ce que j'ai trouvé dans mes recherches avant de devoir passer à une autre tâche. Si vous voulez plus de renseignements ou des exemples, veuillez les commenter.

mise à JOUR . Ben Constable a une grande série sur la façon de implémenter IScrollInfo .

il y a 4 articles au total. Une très bonne lecture.

j'ai depuis mis en place un panneau wrap virtualisé, ce n'est pas une tâche facile, même avec l'aide de la série d'articles ci-dessus.

21
répondu Dennis 2013-03-04 15:25:02

dans mon cas, la meilleure option était d'utiliser:

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

cela m'a donné un analogue décent à L'option Liste de L'Explorateur de Windows

8
répondu Arsen Zahray 2012-05-04 14:01:45

de gauche à droite puis de haut en bas utiliser

      <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" 
                     MaxWidth="{Binding ActualWidth, Mode=OneWay, 
                       RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type er:MainWindow}}}"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
2
répondu kns98 2014-06-23 17:37:08

en plus de la réponse de @Dennis, à propos de la perte de virtualisation du WrapPanel, j'ai trouvé une classe sympa qui implémente correctement ceci. Alors que le post suggéré par Ben Constable ( Partie 1 , Partie 2 , Partie 3 , Partie 4 ) est une belle introduction, Je ne pouvais pas tout à fait compléter la tâche pour un panneau enveloppant.

Voici une implémentation: https://virtualwrappanel.codeplex.com / Je l'ai testé avec un total de 3.300 vidéos et photos, le chargement de la liste elle-même est bien sûr un peu long, mais il finit par virtualiser correctement la liste, sans aucun retard de scroll.

  • il y a des questions à ce code, voir l'onglet questions sur la page ci-dessus.

après avoir ajouté le code source à votre projet, exemple de code source:

   <!--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 style back-end, donc c'est à l'intérieur du 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
répondu CularBytes 2016-05-09 19:48:29