Почему не запускается MeasureOverride?

У меня есть два пользовательских элемента управления для отображения коллекций комментариев и подписей. Каждый из этих элементов управления имеет кнопку для изменения стиля отображения - показать всю коллекцию или только первые 4 элемента.

Когда я помещаю эти элементы управления в WrapPanel по умолчанию - они работают нормально: разворачиваются или сворачиваются в зависимости от действий пользователя. В моем собственном WrapPanel с новой функцией ArrangeOverride они также работают нормально.

Теперь мне нужен WrapPanel с опцией "LastChildFill" (я нашел пример здесь) и с настраиваемым "WrapDirection" (аналогично FlowDirection). Первый или последний элемент в WrapPanel должен заполнить все оставшееся пространство, пока оно больше MinWidth элемента. Итак, я создал третью WrapPanel с пользовательскими MeasureOverride и ArrangeOverride. И это работает, как я хочу, но когда я меняю стиль отображения элемента управления, коллекция внутри элемента управления изменяется, но MeasureOverride в моей WrapPanel не запускается, пока я не изменю размер окна.

Обновление: MeasureOverride не запускается для расширения первого или последнего элемента, который заполняет оставшееся пространство. Свертывание для этого элемента работает нормально.

Я не понимаю, что я сломал с пользовательским MeasureOverride?

Обновление 2: я сомневаюсь, что моя проблема похожа на это: MeasureOverride не всегда вызывал изменения свойств детей.

И приложите код MeasureOverride.

public class WrapPanelFlowDirection : WrapPanel
{
    public bool LastChildFill
    {
        get { return (bool)GetValue(LastChildFillProperty); }
        set { SetValue(LastChildFillProperty, value); }
    }

    public static readonly DependencyProperty LastChildFillProperty =
        DependencyProperty.Register("LastChildFill", typeof(bool), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure));

    public WrapDirection WrapDirection
    {
        get { return (WrapDirection)GetValue(WrapDirectionProperty); }
        set { SetValue(WrapDirectionProperty, value); }
    }

    public static readonly DependencyProperty WrapDirectionProperty =
        DependencyProperty.Register("WrapDirection", typeof(WrapDirection), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(WrapDirection.LeftToRight, FrameworkPropertyMetadataOptions.AffectsMeasure));

    #region Measure Override

    protected override Size MeasureOverride(Size availableSize)
    {
        var panelSize = new Size(availableSize.Width, 0);
        double minWidth = 0;

        foreach (FrameworkElement child in this.InternalChildren)
        {
            child.Measure(availableSize);
            minWidth += child.DesiredSize.Width;
        }

        int firstChildInLine = 0;
        double currLineHeight = 0;
        double currLineWidth = 0;
        UIElementCollection children = this.InternalChildren;

        for (int i = 0; i < children.Count; i++)
        {
            FrameworkElement child = children[i] as FrameworkElement;
            if (child == null)
                continue;

            double w = 0;
            if (child.MinWidth == 0)
                w = child.DesiredSize.Width;
            else
                w = child.MinWidth;

            if (currLineWidth + w <= availableSize.Width)
            {
                currLineWidth += w;
                currLineHeight = Math.Max(currLineHeight, child.DesiredSize.Height);
            }
            else
            {
                MeasureOneLine(firstChildInLine, i - 1, ref currLineHeight, availableSize.Width);
                panelSize.Height += currLineHeight;
                currLineWidth = w;
                currLineHeight = child.DesiredSize.Height;
                if (w > availableSize.Width)
                {
                    MeasureOneLine(i, i, ref currLineHeight, availableSize.Width);
                    panelSize.Height += currLineHeight;
                    currLineHeight = currLineWidth = 0;
                    firstChildInLine = i + 1;
                }
                else
                {
                    firstChildInLine = i;
                }
            }

        }

        if (firstChildInLine < children.Count)
        {
            MeasureOneLine(firstChildInLine, children.Count - 1, ref currLineHeight, availableSize.Width);
            panelSize.Height += currLineHeight;
        }

        if (double.IsInfinity(panelSize.Width))
            panelSize.Width = minWidth;
        return panelSize;
    }

    private void MeasureOneLine(int start, int end, ref double height, double totalWidth)
    {
        UIElementCollection children = this.InternalChildren;

        if (WrapDirection == WrapDirection.LeftToRight)
        {
            for (int i = start; i < end; i++)
            {
                FrameworkElement child = children[i] as FrameworkElement;
                if (child == null)
                    continue;

                double w = 0;
                if (child.MinWidth == 0)
                    w = child.DesiredSize.Width;
                else
                    w = child.MinWidth;
                if (i < end)
                {
                    child.Measure(new Size(w, height));
                    totalWidth -= w;
                }
                else
                {
                    child.Measure(new Size(totalWidth, double.PositiveInfinity));
                    height = Math.Max(height, child.DesiredSize.Height);
                }
            }
        }
        else
        {
            for (int i = end; i >= start; i--)
            {
                FrameworkElement child = children[i] as FrameworkElement;
                if (child == null)
                    continue;

                double w = 0;
                if (child.MinWidth == 0)
                    w = child.DesiredSize.Width;
                else
                    w = child.MinWidth;
                if (i > start)
                {
                    child.Measure(new Size(w, height));
                    totalWidth -= w;
                }
                else
                {
                    child.Measure(new Size(totalWidth, double.PositiveInfinity));
                    height = Math.Max(height, child.DesiredSize.Height);
                }
            }
        }
    }

    #endregion

1 ответ

Решение

Я нашел решение здесь: как контейнер узнает, когда ребенок вызвал InvalidateArrange?

И это сработало для меня.

    public static void OnPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        UIElement panel= VisualTreeHelper.GetParent(source) as UIElement;
        if(panel != null)       
            {
                panel.InvalidateMeasure();
                panel.InvalidateArrange();
            }
    }
Другие вопросы по тегам