切入点1:重写MyPanelParent的MeasureOverride()和ArrangeOverride(),研究父如何影响孩子MyPanel的Layout; 切入点2:重写MyPanel.MeasureOverride 另外,观察MyPanel.MeasureOverride传入的参数,为200×980,根据上一节对Measure过程的分析,MeasureOverride传入的参数宽为200是可预知的,因为我们设置了MyPanel1 对Measure过程的影响,它希望MeasureOverride不要关心自身LayoutTransform的影响。 之前,他希望,MeasureOverride只关心内容怎么布置,而不需要关心基类属性的设置对MeasureOverride的影响。 Q3:在父的MeasureOverride当中调用孩子的Measure方法时,传入的参数有没有什么限制?
2.2 MeasureOverride MeasureOverride在派生类中重写,用于测量子元素在布局中所需的大小。 下面这段代码演示了如何使用MeasureOverride和DesiredSize: protected override Size MeasureOverride(Size availableSize) resizingStoryboard.Children.Add(widthAnimation); ContentWidth和ContentHeight改变时调用InvalidateMeasure()请求重新布局,MeasureOverride protected override Size MeasureOverride(Size constraint) { if (_isResizing) return new Size 参考 FrameworkElement.MeasureOverride(Size) Method (System.Windows) Microsoft Docs.html UIElement.DesiredSize
这里自定义的控件也是这样,通过重写 MeasureOverride 可以修改计算自定义控件的大小的方法,从而报告给上一层一个特殊的值。 如我这里的控件是想要上一层给我多大的空间,我就要多大的空间,我可以通过重写 MeasureOverride 方法,返回参数 protected override Size MeasureOverride (Size availableSize) { base.MeasureOverride(availableSize); return availableSize ; } 因为我这个控件里面有一些控件是需要在测量的过程重新给他一个值,我就可以这样写 protected override Size MeasureOverride(Size grid.Height = availableSize.Height; _grid.Width = availableSize.Width; base.MeasureOverride
(constraint); } 分析 在拖动窗体大小时,游戏用户控件BallGame的MeasureOverride方法会触发,对布局进行重新计算; 方法内逻辑: 如果存在一个运动的气球,那么计算 GetMethod("MeasureOverride", BindingFlags.NonPublic | BindingFlags.Instance); var replaceMethod GetMethod("MeasureOverride", BindingFlags.NonPublic | BindingFlags.Instance); var replaceMethod 注意:因为我们使用的随机密钥对,所以您生成的签名和我的肯定不一样: 再调试,能正常拦截MeasureOverride方法了,传入的实例也能正常显示BallGame(就这?对,我搞了2个晚上。。。。) GetMethod("MeasureOverride", BindingFlags.NonPublic | BindingFlags.Instance); var replaceMethod
在 WPF 做自己的面板可以继承Panel ,可以重写两个方法,第一个方法是 MeasureOverride ,重写这个方法可以告诉上一级控件,这个控件需要多大的空间。 首先重写MeasureOverride,因为需要的一般只是做水平等距,所以就需要拿到元素的宽度和高度,把所有的宽度合起来作为这个控件需要的最小宽度,然后拿到所有控件的最大高度作为这个控件的需要高度。 虽然从 MeasureOverride 返回了大小,但是实际上的上一级控件是不是最后给这么大的,还是不知道的。 protected override Size MeasureOverride(Size availableSize) { var size = new Size local:KbiseczvTom> 所有代码: public class KbiseczvTom : Panel { protected override Size MeasureOverride
TextLineBreak previousLineBreak, TextRunCache textRunCache) at System.Windows.Controls.TextBlock.MeasureOverride availableSize) at System.Windows.UIElement.Measure(Size availableSize) at System.Windows.Controls.Grid.MeasureOverride at System.Windows.UIElement.Measure(Size availableSize) at System.Windows.Controls.Decorator.MeasureOverride (Size constraint) at System.Windows.Documents.AdornerDecorator.MeasureOverride(Size constraint) availableSize) at System.Windows.Window.MeasureOverrideHelper(Size constraint) at System.Windows.Window.MeasureOverride
(Size availableSize) { Debug.WriteLine("F1 MeasureOverride"); return base.MeasureOverride 证明了 Loaded 事件符合预期被触发,且重写的 MeasureOverride 方法也符合预期被调用 F1 MeasureOverride F1_Loaded 这就给了许多新手开发者一个误导,误以为自己定义的控件写对了 (Size availableSize) { Debug.WriteLine("F2 MeasureOverride"); return base.MeasureOverride (Size availableSize) { Debug.WriteLine("F1 MeasureOverride"); return base.MeasureOverride 相信此时大家也能猜到 F2 的 Loaded 事件和 MeasureOverride 方法,肯定是不能符合预期的被调用 以上代码放在github 和 gitee 欢迎访问 可以通过如下方式获取本文以上的源代码
在 WPF 做自己的面板可以继承Panel ,可以重写两个方法,第一个方法是 MeasureOverride ,重写这个方法可以告诉上一级控件,这个控件需要多大的空间。 首先重写MeasureOverride,因为需要的一般只是做水平等距,所以就需要拿到元素的宽度和高度,把所有的宽度合起来作为这个控件需要的最小宽度,然后拿到所有控件的最大高度作为这个控件的需要高度。 虽然从 MeasureOverride 返回了大小,但是实际上的上一级控件是不是最后给这么大的,还是不知道的。 protected override Size MeasureOverride(Size availableSize) { var size = new Size local:KbiseczvTom> 所有代码: public class KbiseczvTom : Panel { protected override Size MeasureOverride
Q5: ContentControl的MeasureOverride和ArrangeOverride过程有没有什么特殊之处? Q6: Control的MeasureOverride和ArrangeOverride过程是什么样的? MeasureOverride:Control的父给多大的空间,Control就将其全部给自己的孩子,并返回孩子的DesiredSize。 Q7: ContentPresenter的MeasureOverride和ArrangeOverride是什么样子的? 跟Control一样。 Q8: 能不能在MeasureOverride或者ArrangeOverride当中调用孩子的孩子,也就是孙子的Measure或者Arrange方法? 目前来看,WPF/SL是允许这样做的。
" /> </Canvas> 每当ProgressRing调用MeasureOverrride都重新计算这些值: protected override System.Windows.Size MeasureOverride ; } TemplateSettings = new TemplateSettingValues(Math.Min(width, height)); return base.MeasureOverride 正确的做法是将计算尺寸及改变尺寸的操作都放到最初的MeasureOverride中。 5. 参考 brian dunnington - ProgressRing for Windows Phone 8 FrameworkElement.MeasureOverride(Size) Method
这时候我们可以通过继承Panel,并重写MeasureOverride 和ArrangeOverride 方法,以实现自己的布局,事实上Canvas,Grid,StackPanel就是继承自Panel, 布局过程中,有二个关键的步骤:测量和排列子元素,正好对应MeasureOverride 与ArrangeOverride 二个方法. MeasureOverride 中必须遍历所有子元素,并调用子元素的Measure 方法,以便让布局系统确定每个子元素的 DesiredSize(即:子元素自身希望占据的空间大小),这是在调用 Measure summary> /// <param name="availableSize"></param> /// <returns></returns> protected override Size MeasureOverride summary> /// <param name="availableSize"></param> /// <returns></returns> protected override Size MeasureOverride
UniformGrid.cs 该类主要是 UnifromGrid 在 Grid 类基础上的处理,主要处理测量和排列的方法,我们来看一下功能比较复杂的 MeasureOverride() 方法,ArrangeOverride MeasureOverride() 首先根据可见元素集合,获取控件的行列数量,设置行列定义; 遍历所有可见元素,根据每个元素的行列和行列跨度属性,设置自动布局,填充 spotsTaken; 计算行和列的空白空间总数值 再根据总空间数值和行列数,计算出一个元素的尺寸; 遍历所有可见元素,找出元素中最大的宽度和高度;再用这个最大尺寸,乘上行列数,加上空白空间数值,得到控件所需尺寸; protected override Size MeasureOverride maxWidth * (double)columns) + columnSpacingSize, (maxHeight * (double)rows) + rowSpacingSize); base.MeasureOverride
Padding, DesiredColumnWidth private 变量:_columnWidth public 方法:StaggeredPanel() protected override 方法:MeasureOverride OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp) { InvalidateMeasure(); } 然后来看两个 override 方法:MeasureOverride (availableSize) 和 ArrangeOverride(finalSize) MeasureOverride(availableSize) : 该方法作用是传入可用的尺寸,基于其对子元素大小的计算确定它在布局期间所需要的尺寸 数组中 ,找到最大值,返回新的尺寸:宽度为可用尺寸的宽度,高度为列数组的最大值;可以看出,这个尺寸就是根据子元素计算出的 panel 需要的空间大小; protected override Size MeasureOverride columnHeights[columnIndex] += elementSize.Height; } return base.ArrangeOverride(finalSize); } 最后来看一下前面 MeasureOverride
布局面板的基类Panel提供了MeasureOverride和ArrangeOverride两个方法,供子类继承实现特定的布局行为。 然后是重写MeasureOverride和ArrangeOverride方法。 } } return list; } protected override Size MeasureOverride
element.DesiredSize)); } return finalSize; } protected override Size MeasureOverride
LongTimeView() { InitializeComponent(); } protected override Size MeasureOverride (Size constraint) { Thread.Sleep(500); return base.MeasureOverride(constraint
性能可控:通过自定义测量(MeasureOverride)和排列(ArrangeOverride)逻辑,优化渲染效率。无冗余功能:仅实现必要特性,避免 TreeView 的额外开销。 string ParentUid { get; set; } }拿垂直布局来说,这里垂直指的终端元素垂直1、了解布局控件自定义ClusterPanel继承自Panel,有两个非常重要的方法,一个是测量MeasureOverride ArrangeOverride,我们自定义布局控件绕不开这两个方法,我们通过ArrangeOverride将标签排到最右侧,空出左侧绿色部分供我们进行画图protected override Size MeasureOverride
ApplyProjection(element, proj, storyboard) 是应用获取到的 Projection,包括旋转,变换等动画; 而因为 CarouselPanel 类继承自 Panel 类,所以它也重写了 MeasureOverride (availableSize) 和 ArrangeOverride(finalSize) 方法: MeasureOverride(availableSize) 方法的实现中,主要是根据宽度和高度是否设置为无限值 ,如果是,且方向和元素排列顺序一致,则尺寸为当前方向三个元素的宽度,然后把计算后的尺寸传出去; protected override Size MeasureOverride(Size availableSize
每个Panel都提供了自己的MeasureOverride和ArrangeOverride方法,以实现自己特定的布局行为。 所以,要实现自定义布局控件,需要继承于Panel类并重写MeasureOverride和ArrangeOverride方法即可,下面实现了一个简单的自定义布局控件: namespace CustomLayoutControl } // 重写默认的Measure方法 // avaiableSize是自定义布局控件的可用大小 protected override Size MeasureOverride } return finalSize; } } } 控件的最终大小和位置是由该控件和父控件共同完成的,父控件会先给子控件提供可用大小(MeasureOverride 这个过程是通过MeasureOverride和ArrangeOverride这两个方法共同完成的,这里需要注意:父控件的availableSize是减去Margin、Padding等的值。
获取子元素可以通过重写 MeasureOverride 第一步,测量子元素,通过子元素可以获得高度宽度 Child.Measure(constraint); 定义自己的 那么计算得到自己的大小就是 子元素的宽高加上 padding 加上气泡需要的外框 因为对于高度,需要加上气泡的高度 5 才可以,代码很容易就看懂,我就不说啦 protected override Size MeasureOverride