WPF ListView与项目的水平排列?

时间:2009-06-24 23:55:07

标签: wpf listview layout

我希望以类似于列表模式下的WinForms ListView的方式在ListView中布置项目。也就是说,在ListView中,项目不仅在垂直方向而且在水平方向上布局。

我不介意这些项目的布局如下:

1 4 7
2 5 8
3 6 9

或者像这样:

1 2 3
4 5 6
7 8 9

只要它们在垂直和水平方向呈现,以便最大限度地利用可用空间。

我能找到的最接近的是这个问题:

How do I make WPF ListView items repeat horizontally, like a horizontal scrollbar?

只能水平放置项目。

5 个答案:

答案 0 :(得分:100)

听起来你正在寻找的是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,您可以从ItemsControls使用的默认StackPanel更改它。使用WrapPanel,我们还应将宽度设置为shown here

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

答案 1 :(得分:21)

我最近研究如何在WPF中实现这一点,并找到了一个很好的解决方案。我想要的是在Windows资源管理器中复制列表模式,即从上到下,然后从左到右。

基本上你想要做什么覆盖ListBox.ItemsPanel属性以使用WrapPanel,其方向设置为Vertical。

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

然而,当加载大型数据集时, WILL 会变慢,因为包装面板未进行虚拟化。这个很重要。因此,现在您需要通过扩展VirtualizedPanel并实现IScrollInfo来编写自己的VirtualizedWrapPanel,此任务现在变得更加重要。

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

这是我在进行另一项任务之前的研究。如果您想了解更多信息或示例,请发表评论。

<强>更新即可。 Ben Constable有一个很棒的series on how to implement IScrollInfo

共有4篇文章。一个非常好的阅读。

我已经实现了虚拟化的包装面板,即使在上述系列文章的帮助下也不是一件容易的事。

答案 2 :(得分:8)

就我而言,最好的选择是使用:

        <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资源管理器的列表选项

答案 3 :(得分:2)

从左到右,然后从上到下使用

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

答案 4 :(得分:2)

除了@Dennis的回答,关于WrapPanel失去Virtualization,我找到了一个很好的类来正确实现它。虽然Ben Constable(Part 1Part 2Part 3Part 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++;
    }
}