VirtualizingStackPanel には 2 つのモードがあります。1 つは ScrollToContent と呼ばれ、そのようなモードでは、VirtualizingStackPanel はアイテムのインデックスを使用します。例として、10 個のアイテムが表示され、1000 個のアイテムがあるため、ScrollBar は小さく表示されます。
2 番目のモードは ScrollToPixels と呼ばれ、このモードでは VirtualizingStackPanel が仮想化されたアイテムと実現されたアイテムのリストを管理します。項目がまだ認識されていない場合、VirtualizingStackPanel はその MinHeight 値を使用します。これは、Microsoft の場合、ユーザーによって設定されていない場合は 16 ピクセルです。例として、10 個のアイテムが表示され、各アイテムの高さは 20 ピクセルです。ビューポートの高さは 200 ピクセルになりますが、アイテムの総数が 1000 であるため、範囲は 200 + (1000 - 10 ) * 16 = 16040 ピクセルになります。ScrollBar も小さく、適切な比率で表示されます。
結局のところ、VirtualizingStackPanel は複雑なものであり、ほとんどの場合うまく機能します。また、垂直方向と水平方向の仮想化も可能です。これは素晴らしいことです。独自の VirtualizingStackPanel を作成する場合は、車輪の再発明をやめることをお勧めします。マイクロソフトの連中が行ったのと同じことをコードで行うことになるので、他の誰かが既に VirtualizingStackPanel を開発したときに時間を浪費するのはなぜですか :)
RedGate ツールで VirtualizingStackPanel を反映させました。これを見てください:
private Size ContainerSizeForItem(ItemsControl itemsControl, object item, int index, out UIElement container)
{
Size containerSize;
container = index >= 0 ? ((ItemContainerGenerator)Generator).ContainerFromIndex(index) as UIElement : null;
if (container != null)
{
containerSize = container.DesiredSize;
}
else
{
// It's virtualized; grab the height off the item if available.
object value = itemsControl.ReadItemValue(item, _desiredSizeStorageIndex);
if (value != null)
{
containerSize = (Size)value;
}
else
{
//
// No stored container height; simply guess.
//
containerSize = new Size();
if (Orientation == Orientation.Horizontal)
{
containerSize.Width = ContainerStackingSizeEstimate(itemsControl, /*isHorizontal = */ true);
containerSize.Height = DesiredSize.Height;
}
else
{
containerSize.Height = ContainerStackingSizeEstimate(itemsControl, /*isHorizontal = */ false);
containerSize.Width = DesiredSize.Width;
}
}
}
return containerSize;
}
private double ContainerStackingSizeEstimate(IProvideStackingSize estimate, bool isHorizontal)
{
double stackingSize = 0d;
if (estimate != null)
{
stackingSize = estimate.EstimatedContainerSize(isHorizontal);
}
if (stackingSize <= 0d || DoubleUtil.IsNaN(stackingSize))
{
stackingSize = ScrollViewer._scrollLineDelta;
}
return stackingSize;
}
ScrollViewer を反映すると、次のようになります。
internal const double _scrollLineDelta = 16.0; // Default physical amount to scroll with one Up/Down
ご覧のとおり、コンテナが利用できない場合、サイズは推測されます。つまり、Microsoft のデフォルトである 16.0 ピクセルに設定されます。
ところで、.Net 3.5以降、たとえばTreeViewを参照してください。:) :)