Wpf 为什么ListBoxItem在宽度更改时不调用MeasureOverride?

Wpf 为什么ListBoxItem在宽度更改时不调用MeasureOverride?,wpf,layout,listboxitem,measureoverride,arrangeoverride,Wpf,Layout,Listboxitem,Measureoverride,Arrangeoverride,好的,为了便于说明,下面我创建了ListBoxItem的一个子类和ListBox的一个子类,它通过重写IsItemTownContainerOverride和GetContainerForItemOverride将其用作容器 现在,当窗口第一次出现时,正如预期的那样,对每个ListBoxItem调用MeasureOverride,其中包含无穷大,然后对每个项调用ArrangeOverride 但是,调整ListBox大小时,仅对ListBoxItem调用ArrangeOverride,而不是Me

好的,为了便于说明,下面我创建了ListBoxItem的一个子类和ListBox的一个子类,它通过重写IsItemTownContainerOverride和GetContainerForItemOverride将其用作容器

现在,当窗口第一次出现时,正如预期的那样,对每个ListBoxItem调用MeasureOverride,其中包含无穷大,然后对每个项调用ArrangeOverride

但是,调整ListBox大小时,仅对ListBoxItem调用ArrangeOverride,而不是MeasureOverride,即使width属性的元数据设置为AffectsMeasure

注意:我知道我可以通过将ScrollViewer.HorizontalScrollbarVisibility设置为“Disabled”来解决这个问题,在这种情况下,MeasureOverride确实会按预期调用,因为滚动设置会强制项目与列表框的宽度匹配,因此自然会重新启动。但是,我仍在试图弄清楚为什么默认情况下不调用度量值,因为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);
    }

}

好的,我认为答案是它没有触发,因为测量过程影响的是面板,而不是项目,面板本身没有调整大小,因此没有理由重新测量其子项

但是,当将ScrollViewer.HorizontalScrollbarVisibility设置为Disabled(禁用)时,面板的宽度跟踪列表框的宽度,而不是其内容,因此需要重新测量子项,这就是为什么会出现这种情况