MeasureOverride ArrangeOverride

本文介绍了自定义容器类中measure和arrange两个关键方法的实现原理。这些方法用于确定子元素的尺寸和位置,从而实现界面布局。文章深入探讨了如何通过层层传递的方式,由上层容器给下层内容分配空间大小。
		protected override Size MeasureOverride(Size constraint)
		{
			if (constraint.Width == double.PositiveInfinity || constraint.Height == double.PositiveInfinity)
				return Size.Empty;

			UpdateScrollInfo(constraint);

			foreach (UIElement child in InternalChildren)
			{
				child.Measure(ChildSize);
			}

			return constraint;
		}

		protected override Size ArrangeOverride(Size finalSize)
		{
			UpdateScrollInfo(finalSize);
			for (int i = 0; i < InternalChildren.Count; i++)
			{
				InternalChildren[i].Arrange(new Rect(new Point(i*ChildSize.Width, 0), ChildSize));
			}
			return finalSize;
		}

层层传递的作用,本自定义容器类定义这两个函数提供给它的上层容器调用,上层容器负责给下层的内容分配空间大小,以此来确定整个界面的布局。
public class ColorBorder : Control { // 定义四个方向的边框画刷依赖属性 public static readonly StyledProperty<IBrush> LeftBorderBrushProperty = AvaloniaProperty.Register<ColorBorder, IBrush>(nameof(LeftBorderBrush)); public IBrush LeftBorderBrush { get => GetValue(LeftBorderBrushProperty); set => SetValue(LeftBorderBrushProperty, value); } // 同样定义TopBorderBrush, RightBorderBrush, BottomBorderBrush public static readonly StyledProperty<IBrush> TopBorderBrushProperty = AvaloniaProperty.Register<ColorBorder, IBrush>(nameof(TopBorderBrush)); public IBrush TopBorderBrush { get => GetValue(TopBorderBrushProperty); set => SetValue(TopBorderBrushProperty, value); } public static readonly StyledProperty<IBrush> RightBorderBrushProperty = AvaloniaProperty.Register<ColorBorder, IBrush>(nameof(RightBorderBrush)); public IBrush RightBorderBrush { get => GetValue(RightBorderBrushProperty); set => SetValue(RightBorderBrushProperty, value); } public static readonly StyledProperty<IBrush> BottomBorderBrushProperty = AvaloniaProperty.Register<ColorBorder, IBrush>(nameof(BottomBorderBrush)); public IBrush BottomBorderBrush { get => GetValue(BottomBorderBrushProperty); set => SetValue(BottomBorderBrushProperty, value); } // 定义边框厚度 public static readonly StyledProperty<Thickness> BorderThicknessProperty = AvaloniaProperty.Register<ColorBorder, Thickness>(nameof(BorderThickness)); public Thickness BorderThickness { get => GetValue(BorderThicknessProperty); set => SetValue(BorderThicknessProperty, value); } // 定义内容(子控件) public static readonly StyledProperty<Control?> ChildProperty = AvaloniaProperty.Register<ColorBorder, Control?>(nameof(Child)); public Control? Child { get => GetValue(ChildProperty); set => SetValue(ChildProperty, value); } // 定义内边距 public static readonly StyledProperty<Thickness> PaddingProperty = AvaloniaProperty.Register<ColorBorder, Thickness>(nameof(Padding)); public Thickness Padding { get => GetValue(PaddingProperty); set => SetValue(PaddingProperty, value); } static ColorBorder() { // 当这些属性改变时,触发重新绘制 AffectsRender<ColorBorder>( LeftBorderBrushProperty, TopBorderBrushProperty, RightBorderBrushProperty, BottomBorderBrushProperty, BorderThicknessProperty ); // 注意:Child的改变需要重新布局,所以需要重写MeasureOverrideArrangeOverride AffectsMeasure<ColorBorder>(ChildProperty); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); // 如果边框厚度改变,也需要重新测量(因为边框厚度可能影响控件的内部空间) if (change.Property == BorderThicknessProperty || change.Property == PaddingProperty) { InvalidateMeasure(); } } // 重写MeasureOverride以测量子控件(如果有) protected override Size MeasureOverride(Size availableSize) { // 计算内部可用空间:总空间减去边框和内边距 Thickness border = BorderThickness; Thickness padding = Padding; Size innerSize = new Size( Math.Max(0, availableSize.Width - border.Left - border.Right - padding.Left - padding.Right), Math.Max(0, availableSize.Height - border.Top - border.Bottom - padding.Top - padding.Bottom) ); // 如果有子控件,则测量子控件 if (Child != null) { Child.Measure(innerSize); return new Size( Child.DesiredSize.Width + border.Left + border.Right + padding.Left + padding.Right, Child.DesiredSize.Height + border.Top + border.Bottom + padding.Top + padding.Bottom ); } // 没有子控件,则返回最小尺寸(边框和内边距) return new Size( border.Left + border.Right + padding.Left + padding.Right, border.Top + border.Bottom + padding.Top + padding.Bottom ); } // 重写ArrangeOverride以安排子控件的位置 protected override Size ArrangeOverride(Size finalSize) { Thickness border = BorderThickness; Thickness padding = Padding; // 计算子控件的布局矩形(在边框和内边距之内) Rect contentRect = new Rect( border.Left + padding.Left, border.Top + padding.Top, Math.Max(0, finalSize.Width - border.Left - border.Right - padding.Left - padding.Right), Math.Max(0, finalSize.Height - border.Top - border.Bottom - padding.Top - padding.Bottom) ); // 如果有子控件,则安排子控件 if (Child != null) { Child.Arrange(contentRect); } return finalSize; } // 重写Render方法,绘制四个边框 public override void Render(DrawingContext context) { // 获取控件的边界矩形 Rect bounds = new Rect(0, 0, Bounds.Width, Bounds.Height); // 绘制左边框 if (BorderThickness.Left > 0 && LeftBorderBrush != null) { context.FillRectangle(LeftBorderBrush, new Rect(0, 0, BorderThickness.Left, bounds.Height)); } // 绘制上边框 if (BorderThickness.Top > 0 && TopBorderBrush != null) { context.FillRectangle(TopBorderBrush, new Rect(0, 0, bounds.Width, BorderThickness.Top)); } // 绘制右边框 if (BorderThickness.Right > 0 && RightBorderBrush != null) { context.FillRectangle( RightBorderBrush, new Rect(bounds.Width - BorderThickness.Right, 0, BorderThickness.Right, bounds.Height) ); } // 绘制下边框 if (BorderThickness.Bottom > 0 && BottomBorderBrush != null) { context.FillRectangle( BottomBorderBrush, new Rect(0, bounds.Height - BorderThickness.Bottom, bounds.Width, BorderThickness.Bottom) ); } } }在这个基础上添加背景和圆角属性
09-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值