如何使不适合其 parent 边界的控件消失

How to make a control disappear that doesn't fit into the bounds of its parent

我想创建一个控件(Panel?),它可以容纳多个 child 控件并排列它们。但是我的控件应该只显示完全适合 parent 控件水平边界的 child 控件。所有其他 child 控件根本不应显示(无滚动条)。当我的控件的大小增加时,更多的 child 控件应该在适合增加的边界后立即变得可见。当然,如果我的控件变小,它们应该会再次消失。

现在我使用一个 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

这似乎符合我的要求。但是一旦只剩下一个 child 并且尺寸变得太小甚至无法显示这个 child,它就不会消失。原因是在MeasureOverride中用availableSize(太小的)来衡量child,所以这个child的DesiredSize适合(太小)availableSize.

然后我尝试使用水平StackPanel并仅覆盖ArrangeOverride,让StackPanel进行排列,然后再决定是否删除child (Visibility = 折叠)或不。但是我找不到一种方法来确定 child 是否适合其 parent 的范围,因为我找不到有关 "position" 的信息 child 在它的 parent 里面。有一个 VisualOffset 属性 看起来很有希望,但我无法访问它。

我考虑过覆盖 OnRenderSizeChanged 而不是 ArrangeOverride,但我会遇到同样的问题,如何确定 child 是否适合其 [=54] 的范围=].

你能告诉我如何做我喜欢做的事情吗?

经过大量搜索后,我决定使用水平 StackPanel 并覆盖 ArrangeOverride。我通过反射访问不可访问的 VisualOffset 属性(我知道,它不受欢迎)来检测排列的 child 的位置并决定它是否仍然可见。

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