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

眉间皱痕 提交于 2019-12-18 13:41:21

问题


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.

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.

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.

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>

回答1:


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.

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:

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.



回答2:


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:

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



来源:https://stackoverflow.com/questions/908089/using-wrappanel-and-scrollviewer-to-give-a-multi-column-listbox-in-wpf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!