5

因此,如果项目在滚动区域的末尾被剪切/裁剪,那么拥有一个无铬的集合看起来真的很愚蠢。

我想为仅绘制整个项目而不是项目的集合(ItemsControl/ListBox)创建一个虚拟化面板。例如:

 ______________
|              |
|______________|
 ______________
|              |
|______________|
 ______________
|              |

在此处输入图像描述

我不希望显示第三个部分容器,除非有空间显示整个项目/容器。在示例中,由于空间不足,第三项被裁剪。

有什么建议么?我应该尝试重新发明轮子(建立我自己的VirtualizingWholeItemPanel)吗?

编辑

微软澄清说VirtualizingPanel.ScrollUnit根本不打算执行此功能。看来,它的用途与旧的 onVirtualizingPanel.ScrollUnit非常相似。CanContentScrollScrollViewer

4

1 回答 1

4

我有一个辅助方法,用于确定控件在父容器中是否部分或完全可见。您可能可以将它与 a一起使用Converter来确定项目的可见性。

您的转换器要么需要从 UI 项计算父容器(我的博客有一组可视化树助手,如果您愿意,可以帮助解决这个问题),或者它可能是一个MultiConverter同时接受 UI 项和父容器作为参数。

ControlVisibility ctrlVisibility= 
    WPFHelpers.IsObjectVisibleInContainer(childControl, parentContainer);

if (ctrlVisibility == ControlVisibility.Full 
    || isVisible == ControlVisibility.FullHeightPartialWidth)
{
    return Visibility.Visible;
}
else
{
    return = Visibility.Hidden;
}

确定控件在其父级中的可见性的代码如下所示:

public enum ControlVisibility
{
    Hidden,
    Partial,
    Full,
    FullHeightPartialWidth,
    FullWidthPartialHeight
}


/// <summary>
/// Checks to see if an object is rendered visible within a parent container
/// </summary>
/// <param name="child">UI element of child object</param>
/// <param name="parent">UI Element of parent object</param>
/// <returns>ControlVisibility Enum</returns>
public static ControlVisibility IsObjectVisibleInContainer(
    FrameworkElement child, UIElement parent)
{
    GeneralTransform childTransform = child.TransformToAncestor(parent);
    Rect childSize = childTransform.TransformBounds(
        new Rect(new Point(0, 0), new Point(child.ActualWidth, child.ActualHeight)));

    Rect result = Rect.Intersect(
        new Rect(new Point(0, 0), parent.RenderSize), childSize);

    if (result == Rect.Empty)
    {
        return ControlVisibility.Hidden;
    }
    if (Math.Round(result.Height, 2) == childSize.Height 
        && Math.Round(result.Width, 2) == childSize.Width)
    {
        return ControlVisibility.Full;
    }
    if (result.Height == childSize.Height)
    {
        return ControlVisibility.FullHeightPartialWidth;
    }
    if (result.Width == childSize.Width)
    {
        return ControlVisibility.FullWidthPartialHeight;
    }
    return ControlVisibility.Partial;
}

编辑

做了一些测试,显然转换器在实际呈现控件之前运行。作为一种技巧,如果您使用 aMultiConverter并将其传递ActualHeight给控件,​​它将起作用,这将迫使转换器在控件被渲染时重新评估。

这是我使用的转换器:

public class TestConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        FrameworkElement child = values[0] as FrameworkElement;
        var parent = VisualTreeHelpers.FindAncestor<ListBox>(child);

        ControlVisibility ctrlVisibility =
            VisualTreeHelpers.IsObjectVisibleInContainer(child, parent);

        if (ctrlVisibility == ControlVisibility.Full
            || ctrlVisibility == ControlVisibility.FullHeightPartialWidth)
        {
            return Visibility.Visible;
        }
        else
        {
            return Visibility.Hidden;
        }
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

我使用了您在问题中发布的 XAML,并ListBoxItem.Resources

<ListBox.Resources>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Visibility">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource Converter}">
                    <Binding RelativeSource="{RelativeSource Self}" />
                    <Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" />
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>
</ListBox.Resources>
于 2012-02-23T16:10:53.950 回答