Хорошо, для наглядности ниже я создал подкласс ListBoxItem
и подкласс ListBox
, который использует его в качестве контейнера, переопределяя как IsItemItsOwnContainerOverride
, так и GetContainerForItemOverride
.
Теперь, когдасначала появляется окно, как и ожидалось, MeasureOverride
вызывается для каждого ListBoxItem
(с бесконечностью, бесконечностью), за которым следует ArrangeOverride
для каждого элемента.
Однако при изменении размера ListBox
,на ListBoxItem
вызывается только ArrangeOverride
, а не 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);
}
}