public void Measure(Size availableSize) { if (PreviousAvailableSize == availableSize || Visibility == Visibility.Collapsed) { return; } PreviousAvailableSize = availableSize; var mm = new MinMaxSize(this); Size constrainedAvailableSize = Size.MinMax(availableSize - Margin, mm.MinSize, mm.MaxSize); Size desiredSize = MeasureOverride(constrainedAvailableSize); if (desiredSize.IsInfinite) { throw new InvalidOperationException($"{nameof(MeasureOverride)} must return a finite size."); } UnclippedDesiredSize = desiredSize = Size.Max(desiredSize, mm.MinSize); DesiredSize = Size.Min(Size.Min(desiredSize, mm.MaxSize) + Margin, availableSize); }
public void Arrange(Rect finalRect) { if (finalRect.IsInfinite) { throw new ArgumentException($"{nameof(finalRect)} must be finite.", nameof(finalRect)); } if (RenderSlotRect == finalRect || Visibility == Visibility.Collapsed) { return; } RenderSlotRect = finalRect; Size arrangeSize = Size.Max(RenderSlotRect.Size - Margin, UnclippedDesiredSize); if (Align != Align.Stretch) { arrangeSize.Width = UnclippedDesiredSize.Width; } if (VerticalAlign != VerticalAlign.Stretch) { arrangeSize.Height = UnclippedDesiredSize.Height; } var mm = new MinMaxSize(this); arrangeSize = Size.Min(arrangeSize, Size.Max(UnclippedDesiredSize, mm.MaxSize)); RenderSize = ArrangeOverride(arrangeSize); Size clippedRenderSize = Size.Min(RenderSize, mm.MaxSize); Vector alignOffset = CalculateAlignOffset(RenderSlotRect.Size - Margin, clippedRenderSize); ActualOffset = alignOffset + new Vector(RenderSlotRect.Position) + new Vector(Margin.Left, Margin.Top); LayoutClip = new Rect(-alignOffset, RenderSlotRect.Size - Margin) .Intersect(new Rect(new Size( mm.MaxSize.IsWidthInfinite ? clippedRenderSize.Width : mm.MaxSize.Width, mm.MaxSize.IsHeightInfinite ? clippedRenderSize.Height : mm.MaxSize.Height ))); }
public void Measure (Size availableSize) { if (Visibility == Visibility.Collapsed) { UnclippedDesiredSize = Size.Empty; DesiredSize = Size.Empty; return; } // Apply margin. availableSize is what parent want us to be. Size constrainedAvailableSize = new Size(availableSize.Width - Margin.Width, availableSize.Height - Margin.Height, false); // Apply min/max/currentvalue constraints. MinMaxSize mm = new MinMaxSize(MinHeight, MaxHeight, MinWidth, MaxWidth, Width, Height); constrainedAvailableSize = Size.MinMax(constrainedAvailableSize, mm.MinSize, mm.MaxSize); Size desiredSize = MeasureOverride(constrainedAvailableSize); if (desiredSize.IsInfinite) throw new InvalidOperationException($"{nameof(MeasureOverride)} must return finite size."); // Maximize desiredSize with user provided min size. desiredSize = Size.Max(desiredSize, mm.MinSize); // Here is the "true minimum" desired size - the one that is for sure enough for the control to render its content. // UnclippedDesiredSize is needed in ArrangeCore, because due to the layout protocol, arrange should be called // with constraints greater or equal to child's desired size returned from MeasureOverride. UnclippedDesiredSize = desiredSize; // User-specified max size starts to "clip" the control here. // Starting from this point desiredSize could be smaller than actually needed to render the whole control. desiredSize = Size.Min(desiredSize, mm.MaxSize); // Because of negative margins, clipped desired size may be negative. // In overconstrained scenario, parent wins and measured size of the child, including any sizes set or computed, // cannot be larger than available size. We will clip it later. DesiredSize = Size.Min(desiredSize + Margin, availableSize); }
private Vector CalculateAlignmentOffset () { // Clipped RenderSize differs from RenderSize only what MaxWidth/Height explicitly clip the otherwise good arrangement. // For ex, DS<clientSize but DS>MaxWidth - in this case we should initiate clip at MaxWidth and only show Top-Left portion // of the element limited by Max properties. It is Top-left because in case when we are clipped by container we also degrade // to Top-Left, so we are consistent. MinMaxSize mm = new MinMaxSize(MinHeight, MaxHeight, MinWidth, MaxWidth, Width, Height); return CalculateAlignmentOffsetCore(CalculateClientSize(), Size.Min(RenderSize, mm.MaxSize)); }