分かりやすく説明するために、以下では、と の両方をオーバーライドしてListBoxItem
、 のサブクラスと のサブクラスを作成ListBox
し、コンテナとしてそれを使用しています。IsItemItsOwnContainerOverride
GetContainerForItemOverride
ウィンドウが最初に表示されると、予想どおり、MeasureOverride
( ListBoxItem
Infinity,Infinity を使用して)ArrangeOverride
すべてのアイテムで呼び出され、その後すべてのアイテムで呼び出されます。
ただし、 のサイズを変更する場合、 width プロパティのメタデータが に設定されていても、ListBox
のみArrangeOverride
が呼び出されます。ListBoxItem
MeasureOverride
AffectsMeasure
注:
ScrollViewer.HorizontalScrollbarVisibility
「無効」に設定することでこれを回避できることはわかってMeasureOverride
います。この場合、スクロール設定によりアイテムがリストボックスの幅に一致するように強制され、自然に再起動されるため、期待どおりに呼び出されます。Width
ただし、プロパティのメタデータにAffectsMeasure
フラグが設定されており、ステップによって幅が変化しているため、デフォルトで Measure が呼び出されない理由をまだ理解しようとしています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);
}
}