【问题标题】:List Items Vertically on a WrapPanel and take advantage of multiple columns在 WrapPanel 上垂直列出项目并利用多列
【发布时间】:2012-07-05 21:26:32
【问题描述】:

我需要垂直列出项目(所有大小相同)(使用 ScrollViewer)。如果容器足够大以显示 x

,我希望项目通过 x 列传播

我第一次尝试:

<ScrollViewer>
    <toolkit:WrapPanel Orientation="Horizontal" ItemHeight="30" ItemWidth="100">
        <Button Content="1" />
        <Button Content="2" />
        <Button Content="3" />
        <Button Content="4" />
        <Button Content="5" />
    </toolkit:WrapPanel>
</ScrollViewer>

结果 - WrapPanel 像我想要的那样工作,但我的项目是从“从左到右”排序的(不是垂直的

然后我尝试将 WrapPanel 的方向设置为“垂直”:

结果 - 我的项目是垂直排列的,但没有分布在多列上。

以下是我希望如何呈现项目:

我真的很想避免编写代码来监控控件大小以根据其大小创建/删除列。

【问题讨论】:

    标签: wpf silverlight xaml scrollviewer wrappanel


    【解决方案1】:

    禁用垂直滚动条。这告诉 WPF 使用水平空间。

    Frode,试试这个(VS2017 .NET 4.7.2):

    <Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="WpfApp1.MainWindow" Title="Wrap Panel Test" Height="100" Width="250">
        <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Disabled">
            <WrapPanel Orientation="Vertical">
                <Button Width="100" Content="1" />
                <Button Width="100" Content="2" />
                <Button Width="100" Content="3" />
                <Button Width="100" Content="4" />
                <Button Width="100" Content="5" />
            </WrapPanel>
        </ScrollViewer>
    </Window>
    

    【讨论】:

      【解决方案2】:

      终于得到了一些有用的东西,但它需要代码。当您说我们需要调整 WrapPanel 的高度以使其正常工作时,我同意你们所有人的看法。这是我的解决方案:

      <ScrollViewer x:Name="scroll1" SizeChanged="ScrollViewer_SizeChanged" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
          <toolkit:WrapPanel x:Name="wp1" Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Left" ItemHeight="30" ItemWidth="250" >
              <Button Content="1" />
              <Button Content="2" />
              <Button Content="3" />
              <Button Content="4" />
              <Button Content="5" />
              <Button Content="6" />
              <Button Content="7" />
              <Button Content="8" />
          </toolkit:WrapPanel>
      </ScrollViewer>
      

      这里是代码隐藏:

      private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
      {
          // Stupid magical number because ViewPortHeight is sometimes not accurate
          Double MAGICALNUMBER = 2;
      
          // Ensure ViewPortSize is not 0
          if (scroll1.ViewportWidth <= MAGICALNUMBER || scroll1.ViewportHeight <= MAGICALNUMBER)
              return;
      
          Size contentSize = new Size(scroll1.ViewportWidth - MAGICALNUMBER, scroll1.ViewportHeight - MAGICALNUMBER);
          Size itemSize = new Size(wp1.ItemWidth, wp1.ItemHeight);
      
          Size newSize = CalculateSizeBasedOnContent(contentSize, wp1.Children.Count, itemSize);
      
          wp1.Width = newSize.Width;
          wp1.Height = newSize.Height;
      }
      
      
      private Size CalculateSizeBasedOnContent(Size containerSize, int itemsCount, Size itemSize)
      {
      
          int iPossibleColumns = (int)Math.Floor(containerSize.Width / itemSize.Width);
          int iPossibleRows = (int)Math.Floor(containerSize.Height / itemSize.Height);
      
          // If all items can fit in first column without scrolling (or if container is narrow than the itemWidth)
          if (itemsCount <= iPossibleRows || containerSize.Width < itemSize.Width)
          return new Size(itemSize.Width, (itemsCount * itemSize.Height));
      
          // If all items can fit in columns without scrollbar
          if (iPossibleColumns * iPossibleRows > itemsCount)
          {
          int columnsNeededForDisplay = (int)Math.Ceiling((itemsCount/(Double) iPossibleRows));
          return new Size(columnsNeededForDisplay * itemSize.Width, containerSize.Height);
          }
      
          // Here scrolling is needed even after spreading in columns
          int itemsPerColumn = (int)Math.Ceiling(wp1.Children.Count / (Double)iPossibleColumns);
          return new Size(containerSize.Width, itemsPerColumn * itemSize.Height);
      
      }
      

      【讨论】:

      • 我最近只是在搞乱ScrollViewer.ViewportHeight...也许this answer 的底部可能对您有所帮助?
      • +1:这对我来说非常有用,只是做了一些非常小的调整。感谢您的解决方案! :)
      • 仅供参考:如果您使用 ItemsControl 而不是 WrapPanel 并且动态更改 ItemsSource,则在调整窗口大小之前它不会跟随。我通过使用 LayoutUpdated 事件而不是 SizeChanged 事件来使其工作,这将更频繁地调用,但正如您在 MSDN 上阅读的那样,在弄乱布局时首选。
      【解决方案3】:

      如果没有定义 HeightWrapPanel,这种行为是不可能的

      您可以使用的另一种选择是Grid,在OnLoadedOnSizeChanged 中,它计算可以容纳多少列,然后设置网格的行/列定义和Grid.Row/@987654327 @ 代码隐藏中的每个对象。它不是很漂亮,但它应该很容易组合起来并且可以工作。

      另一种选择是创建您自己的自定义面板,按照您的需要排列项目。您甚至可以在网上找到一些已经可以做到的东西

      【讨论】:

        【解决方案4】:

        使用WrapPanel 执行此操作的唯一方法是显式设置Height

        看起来您希望项目在列上均匀分布,左列最多比右列多一个项目。如果那是您正在寻找的内容,那么您需要创建自己的自定义面板。查看this 了解如何开始。您需要一个 ItemWidth 和 ItemHeight 依赖属性,并使用 ItemWidth 和可用宽度计算您可以拥有的列数。

        【讨论】:

          【解决方案5】:

          如果您将Orientation 设置为Vertical,您还应该设置渲染高度。例如WrapPanelHeight="150"

          【讨论】:

          • 我希望 WrapPanel 的高度是动态的,以占据在 2 列中显示项目所需的垂直空间(或 3 列或 4 列等。取决于控件的宽度)
          • @danbord,它不是那样工作的。 WrapPanel 将垂直放置适合第一列的所有项目,并将所有左侧的项目分散到下一列。在您的情况下,WrapPanel 会将所有项目放在一列中,因为高度有限制。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-27
          • 2018-12-22
          • 1970-01-01
          相关资源
          最近更新 更多