/// <summary> /// Provides the behavior for the "Measure" pass of layout. /// </summary> /// <param name="availableSize">The available size that this element can /// give to child elements. Infinity can be specified as a value to /// indicate that the element will size to whatever content is available.</param> /// <returns>The size that this element determines it needs during /// layout, based on its calculations of child element sizes.</returns> protected override Size MeasureOverride(Size availableSize) { FrameworkElement child = Child; if (_layoutRoot == null || child == null) { // No content, no size return Size.Empty; } Size measureSize; if (_childActualSize == Size.Empty) { // Determine the largest size after the transformation measureSize = ComputeLargestTransformedSize(availableSize); } else { // Previous measure/arrange pass determined that Child.DesiredSize was larger than believed. measureSize = _childActualSize; } // Perform a mesaure on the _layoutRoot (containing Child) _layoutRoot.Measure(measureSize); // Transform DesiredSize to find its width/height Rect transformedDesiredRect = MatrixHelperEx.RectTransform(new Rect(0, 0, _layoutRoot.DesiredSize.Width, _layoutRoot.DesiredSize.Height), _transformation); Size transformedDesiredSize = new Size(transformedDesiredRect.Width, transformedDesiredRect.Height); // Return result to allocate enough space for the transformation return transformedDesiredSize; }
/// <summary> /// Provides the behavior for the "Arrange" pass of layout. /// </summary> /// <param name="finalSize">The final area within the parent that this /// element should use to arrange itself and its children.</param> /// <returns>The actual size used.</returns> protected override Size ArrangeOverride(Size finalSize) { FrameworkElement child = Child; if (_layoutRoot == null || child == null) { // No child, use whatever was given return(finalSize); } // Determine the largest available size after the transformation Size finalSizeTransformed = ComputeLargestTransformedSize(finalSize); if (IsSizeSmaller(finalSizeTransformed, _layoutRoot.DesiredSize)) { // Some elements do not like being given less space than they asked for (ex: TextBlock) // Bump the working size up to do the right thing by them finalSizeTransformed = _layoutRoot.DesiredSize; } // Transform the working size to find its width/height Rect transformedRect = MatrixHelperEx.RectTransform(new Rect(0, 0, finalSizeTransformed.Width, finalSizeTransformed.Height), _transformation); // Create the Arrange rect to center the transformed content Rect finalRect = new Rect( -transformedRect.Left + ((finalSize.Width - transformedRect.Width) / 2), -transformedRect.Top + ((finalSize.Height - transformedRect.Height) / 2), finalSizeTransformed.Width, finalSizeTransformed.Height); // Perform an Arrange on _layoutRoot (containing Child) _layoutRoot.Arrange(finalRect); // This is the first opportunity to find out the Child's true DesiredSize if (IsSizeSmaller(finalSizeTransformed, child.RenderSize) && (Size.Empty == _childActualSize)) { // Unfortunately, all the work so far is invalid because the wrong DesiredSize was used // Make a note of the actual DesiredSize _childActualSize = new Size(child.ActualWidth, child.ActualHeight); // Force a new measure/arrange pass InvalidateMeasure(); } else { // Clear the "need to measure/arrange again" flag _childActualSize = Size.Empty; } // Return result to perform the transformation return(finalSize); }