Почему ListBoxItem не вызывает MeasureOverride при изменении его ширины?

Хорошо, для наглядности ниже я создал подкласс ListBoxItem и подкласс ListBox который использует его в качестве контейнера, переопределяя оба IsItemItsOwnContainerOverride а также GetContainerForItemOverride,

Теперь, когда окно появляется впервые, как и ожидалось, MeasureOverride называется на каждом ListBoxItem (с Бесконечностью, Бесконечностью) с последующим ArrangeOverride вызывается на каждый предмет.

Однако при изменении размера ListBox, только ArrangeOverride называется на ListBoxItemне MeasureOverride даже если метаданные для свойства width установлены в AffectsMeasure,

Примечание: я знаю, что могу обойти это, установив ScrollViewer.HorizontalScrollbarVisibility "Отключено" в этом случае MeasureOverride действительно вызывается, как и ожидалось, потому что этот параметр прокрутки заставляет элементы соответствовать ширине списка и, таким образом, естественно перезапускается. Тем не менее, я все еще пытаюсь выяснить, почему Measure не вызывается по умолчанию, так как метаданные для Width собственность имеет AffectsMeasure флаг установлен и ширина меняется с помощью ArrangeOverride шаг.

Является ли этот флаг просто подсказкой для его контейнера и в случае элемента управления, помещенного в ScrollViewer это игнорируется? Я предполагаю, что если вы не отключите прокрутку, у элементов управления будет бесконечная область, доступная для них, поэтому, как только они будут измерены, нет необходимости повторно измерять их снова. Отключите горизонтальную прокрутку, и вы заявляете, что ширина не ограничена, следовательно, MeasureOverride называется снова. Но это всего лишь предположение, хотя и логичное.

Вот пример кода для игры. Создайте новый проект WPF и вставьте его в CodeBehind окна и посмотрите на результаты отладки. Затем установите флаг HorizontalScrollbarVisibility, и вы увидите, что он вызывается.

public partial class MainWindow : Window
{
    public MainWindow(){
        InitializeComponent();
        var items = new List<object>(){ "This is a really, really, really, really long sentence"};
        var lbx = new ListBoxEx { ItemsSource = items };
        this.Content = lbx;
    }

}

public class ListBoxEx : ListBox
{
    protected override bool IsItemItsOwnContainerOverride(object item){
        return (item is ListBoxItemEx);
    }

    protected override DependencyObject GetContainerForItemOverride(){
        return new ListBoxItemEx();
    }
}

public class ListBoxItemEx : ListBoxItem
{
    protected override Size MeasureOverride(Size availableSize){
        Console.WriteLine("MeasureOverride called with " + availableSize);
        return base.MeasureOverride(availableSize);
    }

    protected override Size ArrangeOverride(Size finalSize){
        Console.WriteLine("ArrangeOverride called with " + finalSize);
        return base.ArrangeOverride(finalSize);
    }

}

1 ответ

Решение

Хорошо, я думаю, что ответ заключается в том, что он не запускается, потому что проход Measure влияет на панель, а не на элементы, а сама панель не изменила свой размер, поэтому нет причин повторно измерять ее дочерние элементы.

Однако при настройке ScrollViewer.HorizontalScrollbarVisibility в Disabledширина панели отслеживает ширину ListBox, а не его содержимое, поэтому дочерние элементы необходимо повторно измерять, поэтому они и были в этом случае.

Другие вопросы по тегам