Почему 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, а не его содержимое, поэтому дочерние элементы необходимо повторно измерять, поэтому они и были в этом случае.