WPF ListBox WrapPanel剪辑长组
我创建了一个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绑定的副作用。
有什么方法可以启用滚动条,或者有其他方法可以解决这个我没有看到的问题?
解决方案
回答
我认为与绑定有关的是正确的。删除绑定后会发生什么?通过绑定,我们是否要填充至少列表框的整个高度?如果是这样,请考虑绑定到MinHeight,或者尝试使用VerticalAlignment
属性。
回答
大卫,谢谢回答。
当绑定被"删除"时,不会发生换行。 WrapPanel将每个组放入单个垂直列中。
绑定旨在强制WrapPanel实际包装。如果未设置绑定,则WrapPanel假定高度为无穷大且永不环绕。
绑定到" MinHeight"会导致一个空的列表框。我可以看到VerticalAlignment
属性似乎是一个解决方案,但是对齐本身可以防止发生任何换行。当绑定和对齐方式一起使用时,对齐方式不会对问题产生影响。
回答
通过将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)); } }
回答
这是对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)); } }