Virtualizing Panel that doesn't crop items

前端 未结 1 929
感情败类
感情败类 2021-01-13 06:17

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.

I want to create a virtualizing pan

相关标签:
1条回答
  • 2021-01-13 06:28

    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.

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

    Edit

    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.

    Here's the converter I was using:

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

    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>
    
    0 讨论(0)
提交回复
热议问题