100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > WPF自定义控件 —— 布局

WPF自定义控件 —— 布局

时间:2018-10-07 04:18:24

相关推荐

WPF自定义控件 —— 布局

本篇是上一篇自绘的补充,但需要一定的WPF相关知识,感谢Clingingboy 通宵达旦的帮助。

一.ScrollViewer

在前一篇我们做了一个可拖动的矩形,但你是否发现当矩形拖出背景后就不见了,一般来说对于不可见区域需要有ScrollBar来呈现,如图:

对于这一应用在WPF中最常用的应该在控件外面包个ScrollViewer,那么如何使得我们的控件支持ScrollViewer呢?

首先我们来了解一下ScrollViewer基本原理

通过上图我们可以看到ScrollViewer是以Grid为容器组成的控件,其中主要包括ScrollContentPresenter,和两个ScrollBar,其中ScrollBar就是我们第一张图中看到那两条,它也是一个由多个控件组成的复合控件,在这里先略过ScrollBar;来看红色边框内的ScrollContentPresenter,可以看到我们的控件CustomerRender在ScrollContentPresenter内,那么我们控件呈现的位置必定是由它来控制的。

这个神秘的ScrollContentPresenter到底做了什么能让我们看到一部分内容呢?看下这张图就清楚了

我们可以知道ScrollContentPresenter实际对我们玩了一个遮罩效果,把我们的控件当作一个背景图,用ScrollBar来移动背景位置,在ScrollViewer外的控件可视部分统统被裁减掉了。只要继承UIElement的控件就可以重载GetLayoutClip方法来剪切区域。

protected override Geometry GetLayoutClip(Size layoutSlotSize){return new RectangleGeometry(new Rect(base.RenderSize));}

二.ArrangeOverride

ScrollContentPresenter又是如何控制子元素的坐标呢?重载ArrangeOverride函数便可,具体看代码注释

protected override Size ArrangeOverride(Size arrangeBounds){//得到集合中的第一个元素 UIElement visualChild = this.GetVisualChild(0) as UIElement;//把子元素的左上角坐标定义到容器之外 Point point = new Point(-40, -50);if (visualChild != null){Rect finalRect = new Rect(point, visualChild.DesiredSize);//设置元素坐标和大小 visualChild.Arrange(finalRect);}return arrangeBounds;}

这段代码中参数arrangeBounds是父容器传进的值,一般表示你可以有多大的利用空间,这个函数的返回值一般指的是你控件RenderSize的大小.

RenderSize有什么用?(欢迎大家补充)

在onRender里可以用,比如画背景。 在MeasureOverride函数中当参数值为无限大时用来得知可用空间的大小。

三.MeasureOverride

visualChild.DesiredSize的值实际就是我们常用的ActualHeight和ActualWidth的源头,也就是控件的实际大小,我们可以重载MeasureOverride产生。下面是我们的自定义控件用的。

protected override Size MeasureOverride(Size constraint){Size size = new Size(//判断形参constraint中传的值大,还是我们的Rectangle的值大,以最大的那个作为控件的长宽Math.Max(double.IsInfinity(constraint.Width) ? this.RenderSize.Width : constraint.Width, _preivewRectangle.Right),Math.Max(double.IsInfinity(constraint.Height) ? this.RenderSize.Height : constraint.Height, _preivewRectangle.Bottom));return size;}

要说明下的是外容器的大小并不会触发MeasureOverride(如把窗体拖大),只会触发ArrangeOverride,如果你要重新为DesiredSize赋值并通知父容器请使用Measure函数,它会调用父控件的OnChildDesiredSizeChanged方法来通知,同理父控件要监听子控件的大小变化只要重载该方法即可,这个方法可以一直沿着可视树向上引发InvalidateMeasure函数,InvalidateMeasure通过DispatcherPriority为Render来异步调用Measure。

ArrangeOverride中尽量不要调用本身的Measure,Measure函数会再次调用InvalidateArrange方法从而引起循环。控件容器放生变化时可以重载OnRenderSizeChanged实现。

Measure和Arrange的具体关系如下图:

四.补充

如果想要自定义的ScrollBar你可以能要根绝ScrollBar的值实时进行重绘图,这个好处是数据量大,你只需呈现当前画面中的图形,缺点是动一动就要重绘。通过例如ScrollViewer裁减的方式,遮罩得时候不会重绘,不过刚开始呈现的时候数据量大会慢。

另外在复合控件中配合Transform中的各种类来进行布局,使用CompositionTarget和动画类可以产生很多效果。

本例下载

转载请注明

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。