private void InnerMeasureCore(Size availableSize) { var(minSize, maxSize) = this.GetMinMax(); var marginSize = this.GetMarginSize(); // NaN values are accepted as input here, particularly when coming from // SizeThatFits in Image or Scrollviewer. Clamp the value here as it is reused // below for the clipping value. availableSize = availableSize .NumberOrDefault(MaxSize); var frameworkAvailableSize = availableSize .Subtract(marginSize) .AtLeastZero() .AtMost(maxSize); var desiredSize = MeasureOverride(frameworkAvailableSize); _logDebug?.Trace($"{DepthIndentation}{FormatDebugName()}.MeasureOverride(availableSize={frameworkAvailableSize}): desiredSize={desiredSize} minSize={minSize} maxSize={maxSize} marginSize={marginSize}"); if ( double.IsNaN(desiredSize.Width) || double.IsNaN(desiredSize.Height) || double.IsInfinity(desiredSize.Width) || double.IsInfinity(desiredSize.Height) ) { throw new InvalidOperationException($"{FormatDebugName()}: Invalid measured size {desiredSize}. NaN or Infinity are invalid desired size."); } desiredSize = desiredSize .AtLeast(minSize) .AtLeastZero(); _unclippedDesiredSize = desiredSize; var clippedDesiredSize = desiredSize .Add(marginSize) // Making sure after adding margins that clipped DesiredSize is not bigger than the AvailableSize .AtMost(availableSize) // Margin may be negative .AtLeastZero(); // DesiredSize must include margins LayoutInformation.SetDesiredSize(this, clippedDesiredSize); _logDebug?.Debug($"{DepthIndentation}[{FormatDebugName()}] Measure({Name}/{availableSize}/{Margin}) = {clippedDesiredSize} _unclippedDesiredSize={_unclippedDesiredSize}"); }
partial void OnMeasurePartial(Size slotSize) { MeasureCallCount++; AvailableMeasureSize = slotSize; if (DesiredSizeSelector != null) { var desiredSize = DesiredSizeSelector(slotSize); LayoutInformation.SetDesiredSize(this, desiredSize); RequestedDesiredSize = desiredSize; } else if (RequestedDesiredSize != null) { var desiredSize = RequestedDesiredSize.Value; LayoutInformation.SetDesiredSize(this, desiredSize); } }
public void When_UpdateLayout_Then_TreeNotMeasuredUsingCachedValue() { if (Window.Current.RootElement is Panel root) { var sut = new Grid { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; var originalRootAvailableSize = LayoutInformation.GetAvailableSize(root); var originalRootDesiredSize = LayoutInformation.GetDesiredSize(root); var originalRootLayoutSlot = LayoutInformation.GetLayoutSlot(root); Size availableSize; Rect layoutSlot; try { LayoutInformation.SetAvailableSize(root, default); LayoutInformation.SetDesiredSize(root, default); LayoutInformation.SetLayoutSlot(root, default); root.Children.Add(sut); sut.UpdateLayout(); availableSize = LayoutInformation.GetAvailableSize(sut); layoutSlot = LayoutInformation.GetLayoutSlot(sut); } finally { LayoutInformation.SetAvailableSize(root, originalRootAvailableSize); LayoutInformation.SetDesiredSize(root, originalRootDesiredSize); LayoutInformation.SetLayoutSlot(root, originalRootLayoutSlot); root.Children.Remove(sut); try { root.UpdateLayout(); } catch { } // Make sure to restore visual tree if test has failed! } Assert.AreNotEqual(default, availableSize);