如何使不适合其父级范围的控件消失

时间:2019-06-16 07:56:37

标签: wpf vb.net panel

我想创建一个控件(Panel?),它可以容纳多个子控件并进行排列。但是我的控件只应显示水平完全适合于父控件范围的子控件。所有其他子控件均不应显示(无滚动条)。当我的控件的大小增加时,更多的子控件应尽快出现在增加的范围内。当然,如果我的控件尺寸变小,它们应该再次消失。

现在,我将ItemsControl与自定义面板一起用作其ItemPanel,并且此自定义面板是我的控件。

首先,我试图从头开始创建一个自定义面板(继承自Panel),但是我无法一直进行测量和整理工作。

Protected Overrides Function MeasureOverride(availableSize As Size) As Size
    Dim result As Size

    For Each child As UIElement In Me.InternalChildren
        child.Measure(availableSize)

        result.Width += child.DesiredSize.Width
        result.Height = Math.Max(result.Height, child.DesiredSize.Height)
    Next child

    Return New Size(Math.Min(result.Width, availableSize.Width), Math.Min(result.Height, availableSize.Height))
End Function

Protected Overrides Function ArrangeOverride(finalSize As Size) As Size
    Dim left As Double
    Dim bounds As Rect

    left = 0.0

    For Each child As UIElement In Me.InternalChildren
        If ((left + child.DesiredSize.Width) > finalSize.Width) Then
            child.Arrange(New Rect)
        Else
            bounds = New Rect
            bounds.X = left
            bounds.Y = 0
            bounds.Width = child.DesiredSize.Width
            bounds.Height = child.DesiredSize.Height

            child.Arrange(bounds)
        End If

        left += child.DesiredSize.Width
    Next child

    Return finalSize
End Function

这似乎按照我想要的方式工作。但是,一旦只剩下一个孩子,并且尺寸变得太小而无法显示这个孩子,它就不会消失。原因是在MeasureOverride中,availableSize(太小了)用于测量孩子,因此该孩子的DesiredSize恰好适合(太小){{1 }}。

然后,我尝试使用水平availableSize并仅覆盖StackPanel,让ArrangeOverride进行整理,然后再决定是否删除孩子(StackPanel =折叠)。但是我找不到一种方法来决定孩子是否适合其父母的边界,因为我找不到有关孩子在其父母内部的“位置”的信息。有一个Visibility属性看起来很有希望,但我无法访问它。

我曾考虑取代VisualOffset而不是OnRenderSizeChanged,但是我会遇到同样的问题,即如何决定孩子是否适合其父母的生活。

您能提示我如何做我想做的事吗?

1 个答案:

答案 0 :(得分:0)

经过大量搜索,我决定使用水平StackPanel并覆盖ArrangeOverride。我通过反射访问了无法访问的VisualOffset属性(我知道,这是皱着眉头的),以检测已布置的子项的位置并确定它是否仍然可见。

Protected Overrides Function ArrangeOverride(arrangeSize As Size) As Size
    Dim result As Size
    Dim visualOffset As Vector

    result = MyBase.ArrangeOverride(arrangeSize)

    For Each element As UIElement In MyBase.InternalChildren
        visualOffset = element.GetType.GetProperty("VisualOffset", BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(element)

        If visualOffset.X + element.DesiredSize.Width > MyBase.DesiredSize.Width Then
            element.Arrange(New Rect)   'hide the element without breaking possible Visibility bindings
        End If
    Next element

    Return result
End Function