protected override Size MeasureOverride (Size availableSize)
{
ItemsControl owner = ItemsControl.GetItemsOwner (this);
Size measured = new Size (0, 0);
bool invalidate = false;
int nvisible = 0;
int beyond = 0;
int index;
if (Orientation == Orientation.Horizontal)
index = (int) HorizontalOffset;
else
index = (int) VerticalOffset;
// Ensure we always touch ItemContainerGenerator as by accessing this property
// we hook up to some events on it.
IItemContainerGenerator generator = ItemContainerGenerator;
if (owner.Items.Count > 0) {
GeneratorPosition start;
Size childAvailable;
int insertAt;
// Calculate the child sizing constraints
childAvailable = availableSize;
if (Orientation == Orientation.Vertical) {
childAvailable.Height = double.PositiveInfinity;
if (CanHorizontallyScroll)
childAvailable.Width = double.PositiveInfinity;
} else {
childAvailable.Width = double.PositiveInfinity;
if (CanVerticallyScroll)
childAvailable.Height = double.PositiveInfinity;
}
// Next, prepare and measure the extents of our viewable items...
start = generator.GeneratorPositionFromIndex (index);
insertAt = (start.Offset == 0) ? start.Index : start.Index + 1;
using (generator.StartAt (start, GeneratorDirection.Forward, true)) {
bool isNewlyRealized;
for (int i = index; i < owner.Items.Count && beyond < 2; i++, insertAt++) {
// Generate the child container
UIElement child = (UIElement) generator.GenerateNext (out isNewlyRealized);
if (isNewlyRealized || insertAt >= Children.Count || Children[insertAt] != child) {
// Add newly created children to the panel
if (insertAt < Children.Count) {
InsertInternalChild (insertAt, child);
} else {
AddInternalChild (child);
}
generator.PrepareItemContainer (child);
}
// Call Measure() on the child to both force layout and also so
// that we can figure out when to stop adding children (e.g. when
// we go beyond the viewable area)
child.Measure (childAvailable);
Size size = child.DesiredSize;
nvisible++;
if (Orientation == Orientation.Vertical) {
measured.Width = Math.Max (measured.Width, size.Width);
measured.Height += size.Height;
if (measured.Height > availableSize.Height)
beyond++;
} else {
measured.Height = Math.Max (measured.Height, size.Height);
measured.Width += size.Width;
if (measured.Width > availableSize.Width)
beyond++;
}
}
}
}
// FIXME: this if-check is a workaround for a bug
// exposed by NBC Olympics but should not normally be
// here.
if (nvisible > 0)
RemoveUnusedContainers (index, nvisible);
nvisible -= beyond;
// Update our Extent and Viewport values
if (Orientation == Orientation.Vertical) {
if (ExtentHeight != owner.Items.Count) {
ExtentHeight = owner.Items.Count;
invalidate = true;
}
if (ExtentWidth != measured.Width) {
ExtentWidth = measured.Width;
invalidate = true;
}
if (ViewportHeight != nvisible) {
ViewportHeight = nvisible;
invalidate = true;
}
if (ViewportWidth != availableSize.Width) {
ViewportWidth = availableSize.Width;
invalidate = true;
}
// Massage 'measured' into what Silverlight would return...
measured.Width = Math.Min (measured.Width, availableSize.Width);
if (!Double.IsPositiveInfinity (availableSize.Height))
measured.Height = availableSize.Height;
} else {
if (ExtentHeight != measured.Height) {
ExtentHeight = measured.Height;
invalidate = true;
}
if (ExtentWidth != owner.Items.Count) {
ExtentWidth = owner.Items.Count;
invalidate = true;
}
if (ViewportHeight != availableSize.Height) {
ViewportHeight = availableSize.Height;
invalidate = true;
}
if (ViewportWidth != nvisible) {
ViewportWidth = nvisible;
invalidate = true;
}
// Massage 'measured' into what Silverlight would return...
measured.Height = Math.Min (measured.Height, availableSize.Height);
if (!Double.IsPositiveInfinity (availableSize.Width))
measured.Width = availableSize.Width;
}
if (invalidate && ScrollOwner != null)
ScrollOwner.InvalidateScrollInfo ();
return measured;
}