/// <summary> /// The default implementation of the control's measure pass. /// </summary> /// <param name="availableSize">The size available to the control.</param> /// <returns>The desired size for the control.</returns> /// <remarks> /// This method calls <see cref="MeasureOverride(Size)"/> which is probably the method you /// want to override in order to modify a control's arrangement. /// </remarks> protected virtual Size MeasureCore(Size availableSize) { if (IsVisible) { var margin = Margin; ApplyStyling(); ApplyTemplate(); var constrained = LayoutHelper.ApplyLayoutConstraints( this, availableSize.Deflate(margin)); var measured = MeasureOverride(constrained); var width = measured.Width; var height = measured.Height; { double widthCache = Width; if (!double.IsNaN(widthCache)) { width = widthCache; } } width = Math.Min(width, MaxWidth); width = Math.Max(width, MinWidth); { double heightCache = Height; if (!double.IsNaN(heightCache)) { height = heightCache; } } height = Math.Min(height, MaxHeight); height = Math.Max(height, MinHeight); width = Math.Min(width, availableSize.Width); height = Math.Min(height, availableSize.Height); if (UseLayoutRounding) { var scale = GetLayoutScale(); width = Math.Ceiling(width * scale) / scale; height = Math.Ceiling(height * scale) / scale; } return(NonNegative(new Size(width, height).Inflate(margin))); } else { return(new Size()); } }
/// <summary> /// The default implementation of the control's arrange pass. /// </summary> /// <param name="finalRect">The control's new bounds.</param> /// <remarks> /// This method calls <see cref="ArrangeOverride(Size)"/> which is probably the method you /// want to override in order to modify a control's arrangement. /// </remarks> protected virtual void ArrangeCore(Rect finalRect) { if (IsVisible) { var margin = Margin; var originX = finalRect.X + margin.Left; var originY = finalRect.Y + margin.Top; var availableSizeMinusMargins = new Size( Math.Max(0, finalRect.Width - margin.Left - margin.Right), Math.Max(0, finalRect.Height - margin.Top - margin.Bottom)); var horizontalAlignment = HorizontalAlignment; var verticalAlignment = VerticalAlignment; var size = availableSizeMinusMargins; var scale = GetLayoutScale(); if (horizontalAlignment != HorizontalAlignment.Stretch) { size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - margin.Left - margin.Right)); } if (verticalAlignment != VerticalAlignment.Stretch) { size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - margin.Top - margin.Bottom)); } size = LayoutHelper.ApplyLayoutConstraints(this, size); if (UseLayoutRounding) { size = new Size( Math.Ceiling(size.Width * scale) / scale, Math.Ceiling(size.Height * scale) / scale); availableSizeMinusMargins = new Size( Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale, Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale); } size = ArrangeOverride(size).Constrain(size); switch (horizontalAlignment) { case HorizontalAlignment.Center: case HorizontalAlignment.Stretch: originX += (availableSizeMinusMargins.Width - size.Width) / 2; break; case HorizontalAlignment.Right: originX += availableSizeMinusMargins.Width - size.Width; break; } switch (verticalAlignment) { case VerticalAlignment.Center: case VerticalAlignment.Stretch: originY += (availableSizeMinusMargins.Height - size.Height) / 2; break; case VerticalAlignment.Bottom: originY += availableSizeMinusMargins.Height - size.Height; break; } if (UseLayoutRounding) { originX = Math.Floor(originX * scale) / scale; originY = Math.Floor(originY * scale) / scale; } Bounds = new Rect(originX, originY, size.Width, size.Height); } }
protected virtual void ArrangeCore(Rect finalRect) { if (IsVisible) { var useLayoutRounding = UseLayoutRounding; var scale = LayoutHelper.GetLayoutScale(this); var margin = Margin; var originX = finalRect.X + margin.Left; var originY = finalRect.Y + margin.Top; // Margin has to be treated separately because the layout rounding function is not linear // f(a + b) != f(a) + f(b) // If the margin isn't pre-rounded some sizes will be offset by 1 pixel in certain scales. if (useLayoutRounding) { margin = LayoutHelper.RoundLayoutThickness(margin, scale, scale); } var availableSizeMinusMargins = new Size( Math.Max(0, finalRect.Width - margin.Left - margin.Right), Math.Max(0, finalRect.Height - margin.Top - margin.Bottom)); var horizontalAlignment = HorizontalAlignment; var verticalAlignment = VerticalAlignment; var size = availableSizeMinusMargins; if (horizontalAlignment != HorizontalAlignment.Stretch) { size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - margin.Left - margin.Right)); } if (verticalAlignment != VerticalAlignment.Stretch) { size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - margin.Top - margin.Bottom)); } size = LayoutHelper.ApplyLayoutConstraints(this, size); if (useLayoutRounding) { size = LayoutHelper.RoundLayoutSize(size, scale, scale); availableSizeMinusMargins = LayoutHelper.RoundLayoutSize(availableSizeMinusMargins, scale, scale); } size = ArrangeOverride(size).Constrain(size); switch (horizontalAlignment) { case HorizontalAlignment.Center: case HorizontalAlignment.Stretch: originX += (availableSizeMinusMargins.Width - size.Width) / 2; break; case HorizontalAlignment.Right: originX += availableSizeMinusMargins.Width - size.Width; break; } switch (verticalAlignment) { case VerticalAlignment.Center: case VerticalAlignment.Stretch: originY += (availableSizeMinusMargins.Height - size.Height) / 2; break; case VerticalAlignment.Bottom: originY += availableSizeMinusMargins.Height - size.Height; break; } if (useLayoutRounding) { originX = LayoutHelper.RoundLayoutValue(originX, scale); originY = LayoutHelper.RoundLayoutValue(originY, scale); } Bounds = new Rect(originX, originY, size.Width, size.Height); } }