/// <summary> /// Defines the template for core-level arrange layout definition. /// </summary> /// <remarks> /// In WPF this method is defined on UIElement as protected virtual and has a base implementation. /// FrameworkElement (which derrives from UIElement) creates a sealed implemention, similar to the below, /// which discards UIElement's base implementation. /// </remarks> /// <param name = "finalRect">The final area within the parent that element should use to arrange itself and its child elements.</param> private void ArrangeCore(Rect finalRect) { this.isClippingRequired = false; Size finalSize = finalRect != Rect.Empty ? new Size(finalRect.Width, finalRect.Height) : new Size(); Thickness margin = this.Margin; finalSize = finalSize.Deflate(margin); Size unclippedDesiredSize = this.unclippedSize.IsEmpty ? this.DesiredSize.Deflate(margin) : this.unclippedSize; if (finalSize.Width.IsLessThan(unclippedDesiredSize.Width)) { this.isClippingRequired = true; finalSize.Width = unclippedDesiredSize.Width; } if (finalSize.Height.IsLessThan(unclippedDesiredSize.Height)) { this.isClippingRequired = true; finalSize.Height = unclippedDesiredSize.Height; } if (this.HorizontalAlignment != HorizontalAlignment.Stretch) { finalSize.Width = unclippedDesiredSize.Width; } if (this.VerticalAlignment != VerticalAlignment.Stretch) { finalSize.Height = unclippedDesiredSize.Height; } var minMax = new MinMax(this); double largestWidth = Math.Max(unclippedDesiredSize.Width, minMax.MaxWidth); if (largestWidth.IsLessThan(finalSize.Width)) { finalSize.Width = largestWidth; } double largestHeight = Math.Max(unclippedDesiredSize.Height, minMax.MaxHeight); if (largestHeight.IsLessThan(finalSize.Height)) { finalSize.Height = largestHeight; } Size renderSize = this.ArrangeOverride(finalSize); this.RenderSize = renderSize; var inkSize = new Size( Math.Min(renderSize.Width, minMax.MaxWidth), Math.Min(renderSize.Height, minMax.MaxHeight)); this.isClippingRequired |= inkSize.Width.IsLessThan(renderSize.Width) || inkSize.Height.IsLessThan(renderSize.Height); Size clientSize = finalRect.Size.Deflate(margin); this.isClippingRequired |= clientSize.Width.IsLessThan(inkSize.Width) || clientSize.Height.IsLessThan(inkSize.Height); Vector offset = this.ComputeAlignmentOffset(clientSize, inkSize); offset.X += finalRect.X + margin.Left; offset.Y += finalRect.Y + margin.Top; this.visualOffset = offset; }
/// <summary> /// Implements basic measure-pass layout system behavior. /// </summary> /// <remarks> /// In WPF this method is definded on UIElement as protected virtual and returns an empty Size. /// FrameworkElement (which derrives from UIElement) then creates a sealed implementation similar to the below. /// In XPF UIElement and FrameworkElement have been collapsed into a single class. /// </remarks> /// <param name = "availableSize">The available size that the parent element can give to the child elements.</param> /// <returns>The desired size of this element in layout.</returns> private Size MeasureCore(Size availableSize) { this.ResolveDeferredBindings(this.GetNearestDataContext()); this.OnApplyTemplate(); Thickness margin = this.Margin; Size availableSizeWithoutMargins = availableSize.Deflate(margin); var minMax = new MinMax(this); availableSizeWithoutMargins.Width = availableSizeWithoutMargins.Width.Coerce( minMax.MinWidth, minMax.MaxWidth); availableSizeWithoutMargins.Height = availableSizeWithoutMargins.Height.Coerce( minMax.MinHeight, minMax.MaxHeight); Size size = this.MeasureOverride(availableSizeWithoutMargins); size = new Size(Math.Max(size.Width, minMax.MinWidth), Math.Max(size.Height, minMax.MinHeight)); Size unclippedSize = size; bool isClippingRequired = false; if (size.Width > minMax.MaxWidth) { size.Width = minMax.MaxWidth; isClippingRequired = true; } if (size.Height > minMax.MaxHeight) { size.Height = minMax.MaxHeight; isClippingRequired = true; } Size desiredSizeWithMargins = size.Inflate(margin); if (desiredSizeWithMargins.Width > availableSize.Width) { desiredSizeWithMargins.Width = availableSize.Width; isClippingRequired = true; } if (desiredSizeWithMargins.Height > availableSize.Height) { desiredSizeWithMargins.Height = availableSize.Height; isClippingRequired = true; } this.unclippedSize = isClippingRequired ? unclippedSize : Size.Empty; return desiredSizeWithMargins; }
protected virtual Rect GetClippingRect(Size finalSize) { if (!this.isClippingRequired) { return Rect.Empty; } var max = new MinMax(this); Size renderSize = this.RenderSize; double maxWidth = double.IsPositiveInfinity(max.MaxWidth) ? renderSize.Width : max.MaxWidth; double maxHeight = double.IsPositiveInfinity(max.MaxHeight) ? renderSize.Height : max.MaxHeight; bool isClippingRequiredDueToMaxSize = maxWidth.IsLessThan(renderSize.Width) || maxHeight.IsLessThan(renderSize.Height); renderSize.Width = Math.Min(renderSize.Width, max.MaxWidth); renderSize.Height = Math.Min(renderSize.Height, max.MaxHeight); Thickness margin = this.Margin; double horizontalMargins = margin.Left + margin.Right; double verticalMargins = margin.Top + margin.Bottom; var clientSize = new Size( (finalSize.Width - horizontalMargins).EnsurePositive(), (finalSize.Height - verticalMargins).EnsurePositive()); bool isClippingRequiredDueToClientSize = clientSize.Width.IsLessThan(renderSize.Width) || clientSize.Height.IsLessThan(renderSize.Height); if (isClippingRequiredDueToMaxSize && !isClippingRequiredDueToClientSize) { return new Rect(0d, 0d, maxWidth, maxHeight); } if (!isClippingRequiredDueToClientSize) { return Rect.Empty; } Vector offset = this.ComputeAlignmentOffset(clientSize, renderSize); var clipRect = new Rect(-offset.X, -offset.Y, clientSize.Width, clientSize.Height); if (isClippingRequiredDueToMaxSize) { clipRect.Intersect(new Rect(0d, 0d, maxWidth, maxHeight)); } return clipRect; }