3

我创建了一个 ListBox 来显示组中的项目,当这些组不再适合 ListBox 面板的高度时,它们会从右到左包裹。因此,这些组在列表框中将与此类似,其中每个组的高度是任意的(例如,组 1 是组 2 的两倍):

[ 1 ][ 3 ][ 5 ]
[   ][ 4 ][ 6 ]
[ 2 ][   ]

以下 XAML 可以正常工作,因为它执行换行,并允许在项目从 ListBox 右侧运行时出现水平滚动条。

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

  <ListBox.GroupStyle> 
    <ItemsPanelTemplate> 
      <WrapPanel Orientation="Vertical" 
                 Height="{Binding Path=ActualHeight, 
                          RelativeSource={RelativeSource 
                            FindAncestor, 
                            AncestorLevel=1, 
                            AncestorType={x:Type ScrollContentPresenter}}}"/> 
    </ItemsPanelTemplate> 
  </ListBox.GroupStyle> 
</ListBox>

当一组项目长于 WrapPanel 的高度时,会出现此问题。与允许垂直滚动条出现以查看截止项目组不同,该组中的项目被简单地剪裁。我假设这是 WrapPanel 中的 Height 绑定的副作用 - 滚动条认为它不必启用。

有没有办法启用滚动条,或者我没有看到的解决这个问题的其他方法?

4

4 回答 4

2

通过将 WrapPanel 上的 Height 属性设置为 ScrollContentPresenter 的高度,它永远不会垂直滚动。但是,如果您删除该 Binding,它将永远不会换行,因为在布局过程中,它具有无限的高度来布局。

我建议创建你自己的面板类来获得你想要的行为。有一个单独的依赖属性,您可以将所需的高度绑定到该属性,因此您可以使用它来计算度量中的目标高度并安排步骤。如果任何一个孩子高于所需高度,则使用该孩子的高度作为目标高度来计算环绕。

这是执行此操作的示例面板:

public class SmartWrapPanel : WrapPanel
{
    /// <summary>
    /// Identifies the DesiredHeight dependency property
    /// </summary>
    public static readonly DependencyProperty DesiredHeightProperty = DependencyProperty.Register(
        "DesiredHeight",
        typeof(double),
        typeof(SmartWrapPanel),
        new FrameworkPropertyMetadata(Double.NaN, 
            FrameworkPropertyMetadataOptions.AffectsArrange |
            FrameworkPropertyMetadataOptions.AffectsMeasure));

    /// <summary>
    /// Gets or sets the height to attempt to be.  If any child is taller than this, will use the child's height.
    /// </summary>
    public double DesiredHeight
    {
        get { return (double)GetValue(DesiredHeightProperty); }
        set { SetValue(DesiredHeightProperty, value); }
    }

    protected override Size MeasureOverride(Size constraint)
    {
        Size ret = base.MeasureOverride(constraint);
        double h = ret.Height;

        if (!Double.IsNaN(DesiredHeight))
        {
            h = DesiredHeight;
            foreach (UIElement child in Children)
            {
                if (child.DesiredSize.Height > h)
                    h = child.DesiredSize.Height;
            }
        }

        return new Size(ret.Width, h);
    }

    protected override System.Windows.Size ArrangeOverride(Size finalSize)
    {
        double h = finalSize.Height;

        if (!Double.IsNaN(DesiredHeight))
        {
            h = DesiredHeight;
            foreach (UIElement child in Children)
            {
                if (child.DesiredSize.Height > h)
                    h = child.DesiredSize.Height;
            }
        }

        return base.ArrangeOverride(new Size(finalSize.Width, h));
    }
}
于 2008-09-16T17:01:49.503 回答
2

这是稍作修改的代码——所有功劳归功于之前发布的 Abe Heidebrecht——它允许水平和垂直滚动。唯一的变化是MeasureOverride的返回值需要base.MeasureOverride(new Size(ret.width, h))。

// Original code : Abe Heidebrecht
public class SmartWrapPanel : WrapPanel
{
  /// <summary>
  /// Identifies the DesiredHeight dependency property
  /// </summary>
  public static readonly DependencyProperty DesiredHeightProperty = DependencyProperty.Register(
    "DesiredHeight",
    typeof(double),
    typeof(SmartWrapPanel),
    new FrameworkPropertyMetadata(Double.NaN, 
            FrameworkPropertyMetadataOptions.AffectsArrange |
            FrameworkPropertyMetadataOptions.AffectsMeasure));

  /// <summary>
  /// Gets or sets the height to attempt to be.  If any child is taller than this, will use the child's height.
  /// </summary>
  public double DesiredHeight
  {
    get { return (double)GetValue(DesiredHeightProperty); }
    set { SetValue(DesiredHeightProperty, value); }
  }

  protected override Size MeasureOverride(Size constraint)
  {
    Size ret = base.MeasureOverride(constraint);
    double h = ret.Height;

    if (!Double.IsNaN(DesiredHeight))
    {
      h = DesiredHeight;
      foreach (UIElement child in Children)
      {
        if (child.DesiredSize.Height > h)
          h = child.DesiredSize.Height;
      }
    }

    return base.MeasureOverride(new Size(ret.Width, h));
  }

  protected override System.Windows.Size ArrangeOverride(Size finalSize)
  {
    double h = finalSize.Height;

    if (!Double.IsNaN(DesiredHeight))
    {
      h = DesiredHeight;
      foreach (UIElement child in Children)
      {
        if (child.DesiredSize.Height > h)
          h = child.DesiredSize.Height;
      }
    }

    return base.ArrangeOverride(new Size(finalSize.Width, h));
  }
}
于 2008-09-17T12:51:19.473 回答
0

谢谢你的回答,大卫。

当绑定为removed时,不会发生换行。WrapPanel将每个组放入一个垂直列中。

绑定旨在强制 WrapPanel 实际换行。如果没有设置绑定,WrapPanel 假定高度是无限的并且从不换行。

绑定到MinHeight会导致一个空的列表框。我可以看到该VerticalAlignment属性似乎是一种解决方案,但对齐本身可以防止发生任何包装。当绑定和对齐一起使用时,对齐对问题没有影响。

于 2008-09-16T16:36:24.883 回答
0

我认为你是正确的,它与绑定有关。移除绑定后会发生什么?通过绑定,您是否试图至少填满列表框的整个高度?如果是这样,请考虑改为绑定到 MinHeight,或尝试使用该VerticalAlignment属性。

于 2008-09-16T16:27:27.323 回答