protected override Size ArrangeOverride( Size finalSize )
{
// Variables tracking the size of the current line, and the maximum
// size available to fill. Note that the line might represent a row
// or a column depending on the orientation.
Orientation o = Orientation;
OrientedSize lineSize = new OrientedSize( o );
OrientedSize maximumSize = new OrientedSize( o, finalSize.Width, finalSize.Height );
// Determine the constraints for individual items
double itemWidth = ItemWidth;
double itemHeight = ItemHeight;
bool hasFixedWidth = !itemWidth.IsNaN();
bool hasFixedHeight = !itemHeight.IsNaN();
double indirectOffset = 0;
double? directDelta = ( o == Orientation.Horizontal ) ?
( hasFixedWidth ? ( double? ) itemWidth : null ) :
( hasFixedHeight ? ( double? ) itemHeight : null );
// Measure each of the Children. We will process the elements one
// line at a time, just like during measure, but we will wait until
// we've completed an entire line of elements before arranging them.
// The lineStart and lineEnd variables track the size of the
// currently arranged line.
UIElementCollection children = Children;
int count = children.Count;
int lineStart = 0;
for ( int lineEnd = 0; lineEnd < count; lineEnd++ )
{
UIElement element = children[ lineEnd ];
// Get the size of the element
OrientedSize elementSize = new OrientedSize(
o,
hasFixedWidth ? itemWidth : element.DesiredSize.Width,
hasFixedHeight ? itemHeight : element.DesiredSize.Height );
// If this element falls of the edge of the line
if ( NumericExtensions.IsGreaterThan( lineSize.Direct + elementSize.Direct, maximumSize.Direct ) )
{
// Then we just completed a line and we should arrange it
ArrangeLine( lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect );
// Move the current element to a new line
indirectOffset += lineSize.Indirect;
lineSize = elementSize;
// If the current element is larger than the maximum size
if ( NumericExtensions.IsGreaterThan( elementSize.Direct, maximumSize.Direct ) )
{
// Arrange the element as a single line
ArrangeLine( lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect );
// Move to a new line
indirectOffset += lineSize.Indirect;
lineSize = new OrientedSize( o );
}
// Advance the start index to a new line after arranging
lineStart = lineEnd;
}
else
{
// Otherwise just add the element to the end of the line
lineSize.Direct += elementSize.Direct;
lineSize.Indirect = Math.Max( lineSize.Indirect, elementSize.Indirect );
}
}
// Arrange any elements on the last line
if ( lineStart < count )
{
ArrangeLine( lineStart, count, directDelta, indirectOffset, lineSize.Indirect );
}
return finalSize;
}