Как заставить исчезнуть элемент управления, который не вписывается в границы своего родителя - PullRequest
0 голосов
/ 16 июня 2019

Я хотел бы создать элемент управления (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 этого ребенка вписывается в (слишком маленькое) availableSize.

Затем я попытался использовать горизонтальный StackPanel и переопределить только ArrangeOverride, пусть StackPanel выполнит аранжировку и впоследствии решит, удалять ли ребенка (Visibility = Свернули) или нет. Но я не могу найти способ решить, вписывается ли ребенок в границы своего родителя или нет, потому что я не могу найти информацию о «положении» ребенка внутри его родителя. Есть свойство VisualOffset, которое выглядит многообещающим, но я не могу получить к нему доступ.

Я думал о переопределении OnRenderSizeChanged вместо ArrangeOverride, но там у меня возникла бы та же проблема, как решить, подходит ли ребенок в пределы своего родителя.

Можете ли вы дать мне подсказку о том, как делать то, что я люблю делать?

1 Ответ

0 голосов
/ 29 июня 2019

После долгих поисков я решил перейти с горизонтальной 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
...