/// <summary> /// Override for <seealso cref="UIElement.MeasureCore" />. /// </summary> protected sealed override Size MeasureCore(Size availableSize) { Debug.Assert(MeasureData == null || availableSize == MeasureData.AvailableSize, "MeasureData needs to be passed down in [....] with size"); // If using layout rounding, check whether rounding needs to compensate for high DPI bool useLayoutRounding = this.UseLayoutRounding; if (useLayoutRounding) { if (!CheckFlagsAnd(VisualFlags.UseLayoutRounding)) { this.SetFlags(true, VisualFlags.UseLayoutRounding); } } //build the visual tree from styles first ApplyTemplate(); if (BypassLayoutPolicies) { return MeasureOverride(availableSize); } else { Thickness margin = Margin; double marginWidth = margin.Left + margin.Right; double marginHeight = margin.Top + margin.Bottom; MeasureData measureData = MeasureData; // parent size is what parent want us to be Size frameworkAvailableSize = new Size( Math.Max(availableSize.Width - marginWidth, 0), Math.Max(availableSize.Height - marginHeight, 0)); MinMax mm = new MinMax(this); LayoutTransformData ltd = LayoutTransformDataField.GetValue(this); { Transform layoutTransform = this.LayoutTransform; // check that LayoutTransform is non-trivial if (layoutTransform != null && !layoutTransform.IsIdentity) { if (ltd == null) { // allocate and store ltd if needed ltd = new LayoutTransformData(); LayoutTransformDataField.SetValue(this, ltd); } ltd.CreateTransformSnapshot(layoutTransform); ltd.UntransformedDS = new Size(); if (useLayoutRounding) { ltd.TransformedUnroundedDS = new Size(); } } else if (ltd != null) { // clear ltd storage ltd = null; LayoutTransformDataField.ClearValue(this); } } if (ltd != null) { // Find the maximal area rectangle in local (child) space that we can fit, post-transform // in the decorator's measure constraint. frameworkAvailableSize = FindMaximalAreaLocalSpaceRect(ltd.Transform, frameworkAvailableSize); } frameworkAvailableSize.Width = Math.Max(mm.minWidth, Math.Min(frameworkAvailableSize.Width, mm.maxWidth)); frameworkAvailableSize.Height = Math.Max(mm.minHeight, Math.Min(frameworkAvailableSize.Height, mm.maxHeight)); // If layout rounding is enabled, round available size passed to MeasureOverride. if (useLayoutRounding) { frameworkAvailableSize = UIElement.RoundLayoutSize(frameworkAvailableSize, FrameworkElement.DpiScaleX, FrameworkElement.DpiScaleY); } // call to specific layout to measure if (measureData != null) { measureData.AvailableSize = frameworkAvailableSize; } Size desiredSize = MeasureOverride(frameworkAvailableSize); if (measureData != null) { // MeasureData should be treated like a parameter to Measure and thus not modified when returning from this call. measureData.AvailableSize = availableSize; } // maximize desiredSize with user provided min size desiredSize = new Size( Math.Max(desiredSize.Width, mm.minWidth), Math.Max(desiredSize.Height, mm.minHeight)); //here is the "true minimum" desired size - the one that is //for sure enough for the control to render its content. Size unclippedDesiredSize = desiredSize; if (ltd != null) { //need to store unclipped, untransformed desired size to be able to arrange later ltd.UntransformedDS = unclippedDesiredSize; //transform unclipped desired size Rect unclippedBoundsTransformed = Rect.Transform(new Rect(0, 0, unclippedDesiredSize.Width, unclippedDesiredSize.Height), ltd.Transform.Value); unclippedDesiredSize.Width = unclippedBoundsTransformed.Width; unclippedDesiredSize.Height = unclippedBoundsTransformed.Height; } bool clipped = false; // User-specified max size starts to "clip" the control here. //Starting from this point desiredSize could be smaller then actually //needed to render the whole control if (desiredSize.Width > mm.maxWidth) { desiredSize.Width = mm.maxWidth; clipped = true; } if (desiredSize.Height > mm.maxHeight) { desiredSize.Height = mm.maxHeight; clipped = true; } //transform desired size to layout slot space if (ltd != null) { Rect childBoundsTransformed = Rect.Transform(new Rect(0, 0, desiredSize.Width, desiredSize.Height), ltd.Transform.Value); desiredSize.Width = childBoundsTransformed.Width; desiredSize.Height = childBoundsTransformed.Height; } // because of negative margins, clipped desired size may be negative. // need to keep it as doubles for that reason and maximize with 0 at the // very last point - before returning desired size to the parent. double clippedDesiredWidth = desiredSize.Width + marginWidth; double clippedDesiredHeight = desiredSize.Height + marginHeight; // In overconstrained scenario, parent wins and measured size of the child, // including any sizes set or computed, can not be larger then // available size. We will clip the guy later. if (clippedDesiredWidth > availableSize.Width) { clippedDesiredWidth = availableSize.Width; clipped = true; } if (clippedDesiredHeight > availableSize.Height) { clippedDesiredHeight = availableSize.Height; clipped = true; } // Set transformed, unrounded size on layout transform, if any. if (ltd != null) { ltd.TransformedUnroundedDS = new Size(Math.Max(0, clippedDesiredWidth), Math.Max(0, clippedDesiredHeight)); } // If using layout rounding, round desired size. if (useLayoutRounding) { clippedDesiredWidth = UIElement.RoundLayoutValue(clippedDesiredWidth, DpiScaleX); clippedDesiredHeight = UIElement.RoundLayoutValue(clippedDesiredHeight, DpiScaleY); } // Note: 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. But in most circumstances // it is possible to reconstruct original unclipped desired size. // In such cases we want to optimize space and save 16 bytes by // not storing it on each FrameworkElement. // // The if statement conditions below lists the cases when // it is NOT possible to recalculate unclipped desired size later // in ArrangeCore, thus we save it into Uncommon Fields... // // Note 2: use SizeBox to avoid CLR boxing of Size. // measurements show it is better to allocate an object once than // have spurious boxing allocations on every resize SizeBox sb = UnclippedDesiredSizeField.GetValue(this); if (clipped || clippedDesiredWidth < 0 || clippedDesiredHeight < 0) { if (sb == null) //not yet allocated, allocate the box { sb = new SizeBox(unclippedDesiredSize); UnclippedDesiredSizeField.SetValue(this, sb); } else //we already have allocated size box, simply change it { sb.Width = unclippedDesiredSize.Width; sb.Height = unclippedDesiredSize.Height; } } else { if (sb != null) UnclippedDesiredSizeField.ClearValue(this); } return new Size(Math.Max(0, clippedDesiredWidth), Math.Max(0, clippedDesiredHeight)); } }
protected override sealed Size MeasureCore(Size availableSize) { bool useLayoutRounding = this.UseLayoutRounding; if (useLayoutRounding && !this.CheckFlagsAnd(VisualFlags.UseLayoutRounding)) this.SetFlags(true, VisualFlags.UseLayoutRounding); this.ApplyTemplate(); if (this.BypassLayoutPolicies) return this.MeasureOverride(availableSize); Thickness margin = this.Margin; double num1 = margin.Left + margin.Right; double num2 = margin.Top + margin.Bottom; if (useLayoutRounding && this is ScrollContentPresenter) { num1 = UIElement.RoundLayoutValue(num1, FrameworkElement.DpiScaleX); num2 = UIElement.RoundLayoutValue(num2, FrameworkElement.DpiScaleY); } Size size1 = new Size(Math.Max(availableSize.Width - num1, 0.0), Math.Max(availableSize.Height - num2, 0.0)); FrameworkElement.MinMax minMax = new FrameworkElement.MinMax(this); FrameworkElement.LayoutTransformData layoutTransformData = FrameworkElement.LayoutTransformDataField.GetValue((DependencyObject) this); Transform layoutTransform = this.LayoutTransform; if (layoutTransform != null && !layoutTransform.IsIdentity) { if (layoutTransformData == null) { layoutTransformData = new FrameworkElement.LayoutTransformData(); FrameworkElement.LayoutTransformDataField.SetValue((DependencyObject) this, layoutTransformData); } layoutTransformData.CreateTransformSnapshot(layoutTransform); layoutTransformData.UntransformedDS = new Size(); if (useLayoutRounding) layoutTransformData.TransformedUnroundedDS = new Size(); } else if (layoutTransformData != null) { layoutTransformData = (FrameworkElement.LayoutTransformData) null; FrameworkElement.LayoutTransformDataField.ClearValue((DependencyObject) this); } if (layoutTransformData != null) size1 = this.FindMaximalAreaLocalSpaceRect(layoutTransformData.Transform, size1); size1.Width = Math.Max(minMax.minWidth, Math.Min(size1.Width, minMax.maxWidth)); size1.Height = Math.Max(minMax.minHeight, Math.Min(size1.Height, minMax.maxHeight)); if (useLayoutRounding) size1 = UIElement.RoundLayoutSize(size1, FrameworkElement.DpiScaleX, FrameworkElement.DpiScaleY); Size size2 = this.MeasureOverride(size1); size2 = new Size(Math.Max(size2.Width, minMax.minWidth), Math.Max(size2.Height, minMax.minHeight)); Size size3 = size2; if (layoutTransformData != null) { layoutTransformData.UntransformedDS = size3; Rect rect = Rect.Transform(new Rect(0.0, 0.0, size3.Width, size3.Height), layoutTransformData.Transform.Value); size3.Width = rect.Width; size3.Height = rect.Height; } bool flag = false; if (size2.Width > minMax.maxWidth) { size2.Width = minMax.maxWidth; flag = true; } if (size2.Height > minMax.maxHeight) { size2.Height = minMax.maxHeight; flag = true; } if (layoutTransformData != null) { Rect rect = Rect.Transform(new Rect(0.0, 0.0, size2.Width, size2.Height), layoutTransformData.Transform.Value); size2.Width = rect.Width; size2.Height = rect.Height; } double val2_1 = size2.Width + num1; double val2_2 = size2.Height + num2; if (val2_1 > availableSize.Width) { val2_1 = availableSize.Width; flag = true; } if (val2_2 > availableSize.Height) { val2_2 = availableSize.Height; flag = true; } if (layoutTransformData != null) layoutTransformData.TransformedUnroundedDS = new Size(Math.Max(0.0, val2_1), Math.Max(0.0, val2_2)); if (useLayoutRounding) { val2_1 = UIElement.RoundLayoutValue(val2_1, FrameworkElement.DpiScaleX); val2_2 = UIElement.RoundLayoutValue(val2_2, FrameworkElement.DpiScaleY); } SizeBox sizeBox1 = FrameworkElement.UnclippedDesiredSizeField.GetValue((DependencyObject) this); if (flag || val2_1 < 0.0 || val2_2 < 0.0) { if (sizeBox1 == null) { SizeBox sizeBox2 = new SizeBox(size3); FrameworkElement.UnclippedDesiredSizeField.SetValue((DependencyObject) this, sizeBox2); } else { sizeBox1.Width = size3.Width; sizeBox1.Height = size3.Height; } } else if (sizeBox1 != null) FrameworkElement.UnclippedDesiredSizeField.ClearValue((DependencyObject) this); return new Size(Math.Max(0.0, val2_1), Math.Max(0.0, val2_2)); }