使用 WrapPanel 和 ScrollViewer 在 WPF 中给出多列列表框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/908089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:28:35  来源:igfitidea点击:

Using WrapPanel and ScrollViewer to give a multi-column Listbox in WPF

wpfdata-bindingxamllistbox

提问by Saqib

I'm making a simple LOB app which loads data from an XML file and displays it in a list with a few buttons for editing.

我正在制作一个简单的 LOB 应用程序,它从一个 XML 文件加载数据并将其显示在一个列表中,并带有几个用于编辑的按钮。

In my first attempt, everything was ok except that the list scrolled downwards in one long column. I would prefer the data to wrap so that at the bottom of the Window it starts a second column, and so on – if you resize the Window the data should resize accordingly.

在我的第一次尝试中,除了列表在一个长列中向下滚动外,一切正常。我希望将数据换行,以便在窗口底部开始第二列,依此类推——如果您调整窗口大小,数据应相应调整大小。

First, I just put the ListBox inside a ScrollViewer. This made no difference whatsoever.

首先,我只是将 ListBox 放在 ScrollViewer 中。这没有任何区别。

Then, I added a WrapPanel within the ItemTemplate. At this point I got a long row horizontally but it never wrapped to a second row, despite my setting the ScrollViewer.HorizontalScrollbar=disabled.

然后,我在 ItemTemplate 中添加了一个 WrapPanel。在这一点上,尽管我设置了 ScrollViewer.Horizo​​ntalScrollbar=disabled,但我在水平方向上得到了一个长行,但它从未换行到第二行。

I've searched around the web on various blogs and forums, but can't see the difference between the suggestions and my code (included below). Any tips would be much appreciated.

我在各种博客和论坛上搜索了网络,但看不到建议和我的代码(包括在下面)之间的区别。任何提示将不胜感激。

<Window x:Class="MyApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="My App" Height="300" Width="400"
        FocusManager.FocusedElement="{Binding ElementName=eventsList}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
                <ScrollViewer Grid.Row="0" Grid.Column="0"     HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
            <ListBox Name="eventsList">
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
            </ListBox>
        </ScrollViewer>

        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal"     HorizontalAlignment="Center" Visibility="Collapsed">
            <Button Name="action1Button" />
            <Button Name="action2Button" />
            <Button Name="action3Button" />
        </StackPanel>
    </Grid>
</Window>

回答by Nicholas Armstrong

It seems like you were on the right track: replacing the ItemsPanelTemplate in the ListBox with a WrapPanel, setting WrapPanel's Orientation to Vertical, and setting ScrollViewer.VerticalScrollBar to Disabled should be all you need to do.

看起来您在正确的轨道上:用 WrapPanel 替换 ListBox 中的 ItemsPanelTemplate,将 WrapPanel 的 Orientation 设置为 Vertical,并将 ScrollViewer.VerticalScrollBar 设置为 Disabled 应该是您需要做的全部。

This works for me:

这对我有用:

<Window x:Class="ScrollingWrapPanel.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListBox ScrollViewer.VerticalScrollBarVisibility="Disabled">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Red"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Orange"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Yellow"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Green"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Blue"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Indigo"/>
            </ListBoxItem>
            <ListBoxItem>
                <Rectangle Width="80" Height="80" Margin="10" Fill="Violet"/>
            </ListBoxItem>
        </ListBox>
    </Grid>
</Window>

That should cause it to render out a full column vertically, wrap, and then continue on the next column, scrolling as necessary horizontally (but not vertically), as in the picture:

这应该会导致它垂直渲染一整列,换行,然后继续下一列,根据需要水平(但不是垂直)滚动,如图所示:

ListBox with WrapPanel wrapping vertically

带有 WrapPanel 的 ListBox 垂直包装

The key things in this implementation are

这个实现的关键是

  1. Setting Orientation="Vertical" on the WrapPanel so that things wrap vertically and not horizontally, and
  2. Setting ScrollViewer.VerticalScrollBarVisibility="Disabled" on the ListBox so that the ScrollViewer knows to restrict its height to the available space.
  1. 在 WrapPanel 上设置 Orientation="Vertical" 以便事物垂直而不是水平包装,并且
  2. 在 ListBox 上设置 ScrollViewer.VerticalScrollBarVisibility="Disabled" 以便 ScrollViewer 知道将其高度限制为可用空间。

回答by Ana Betts

I believe to do this, you need to write custom code - you've got the right idea in overriding ItemsPanelTemplate, but WrapPanel doesn't order stuff the way you want it - it'll order stuff as:

我相信要做到这一点,您需要编写自定义代码 - 您在覆盖 ItemsPanelTemplate 方面有正确的想法,但 WrapPanel 不会按照您想要的方式订购 - 它会按以下方式订购:

A B C D
E F G H
I J K L

Whereas you probably want it:

而你可能想要它:

A D G J
B E H K
C F I L

Also, by putting it in a ScrollViewer, it's like telling it that it has an infinitely sized screen, so the result will just be one row (because the ScrollViewer will give it as much room as it asks for). Writing a panel isn't hard, it's basically just two functions (Measure and Arrange).

此外,通过将它放在 ScrollViewer 中,就像告诉它它有一个无限大小的屏幕,所以结果只会是一行(因为 ScrollViewer 会为其提供所需的空间)。编写面板并不难,它基本上只有两个功能(测量和排列)。