不裁剪项目的虚拟化面板 [英] Virtualizing Panel that doesn't crop items

查看:27
本文介绍了不裁剪项目的虚拟化面板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So, it looks really silly to have a chrome-less collection if the items are getting cut/cropped at the end of the scroll region.

我想为集合 (ItemsControl/ListBox) 创建一个虚拟化面板,它只绘制整个项目,而不是项目的片段.例如:

I want to create a virtualizing panel for collections (ItemsControl/ListBox) that only draws whole items, never pieces of items. For example:

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

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

I don't want the 3rd partial container to be displayed unless there is room for the WHOLE item/container to be displayed. In the examples, the third item was cropped because of a lack of space.

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

Any suggestions? Should I try to reinvent the wheel (build my own VirtualizingWholeItemPanel)?

编辑:

Microsoft 澄清说 VirtualizingPanel.ScrollUnit 根本不打算执行此功能.看起来 VirtualizingPanel.ScrollUnit 的作用与 ScrollViewer 上的旧 CanContentScroll 非常相似.

Microsoft clarified that VirtualizingPanel.ScrollUnit is not intended to perform this functionality at all. It appears that VirtualizingPanel.ScrollUnit serves a very similar purpose to the old CanContentScroll on ScrollViewer.

推荐答案

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

I have a helper method which I use to determine if a control is partially or completly visible within a parent container. You can probably use it with a Converter to determine the items' visibility.

您的转换器要么需要根据 UI 项计算父容器(我的博客有一组 Visual Tree Helpers,如果您愿意,可以提供帮助),或者它可以是一个接受 UI 项和父容器的 MultiConverter作为参数.

Your converter would either need to calculate the parent container from the UI item (My blog has a set of Visual Tree Helpers that could assist with this if you want), or it could be a MultiConverter that accepts both the UI item and the parent container as parameters.

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

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

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

The code to determine a control's visibility within it's parent looks like this:

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;
}

编辑

做了一些测试,显然转换器在控件实际呈现之前运行.作为一个技巧,如果您使用 MultiConverter 并将控件的 ActualHeight 传递给它,它将起作用,这将强制转换器在控件呈现时重新评估.

Did some tests and apparently the converter gets run before controls are actually rendered. As a hack, it will work if you use a MultiConverter and pass it the ActualHeight of the control, which will force the converter to re-evaluate when the control gets rendered.

这是我使用的转换器:

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,并在 .Resources

I used the XAML you posted in your question, and just added an implicit style for ListBoxItem in the .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>

这篇关于不裁剪项目的虚拟化面板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆