zoukankan      html  css  js  c++  java
  • WPF MeasureOverride And ArrangeOverride

    在UIElement布局的时候,我们要知道父窗体或父控件要给子控件分配多少空间,换句话说子控件需要父控件提供多少空间给它。

    这些步骤在什么时候发生呢?

    这些过程来自UIElement的Measure 和Arrange,所以我们来重写这两个方法。看看里面到底做了些什么。

    父MeasureOverride 和ArrangeOverride

    Measure(测量),此方法实现:父元素从其自身的 MeasureCore 实现调用此方法以形成递归布局更新。

    其中Measure方法传入的参数是availableSize,这个availableSize是一个Size类型,表示的是父元素可以提供的大小。

    下面用实例来讲解。

    新建一个PlotPanel类.

       1:  public class PlotPanel:Panel
       2:      {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             Size size=new Size();
       6:             foreach (UIElement child in InternalChildren)
       7:             {
       8:                 child.Measure(availableSize);
       9:                 size = child.DesiredSize;
      10:             }
      11:             return size;
      12:         }
      13:   
      14:         protected override Size ArrangeOverride(Size finalSize)
      15:         {
      16:             foreach (UIElement child in InternalChildren)
      17:             {
      18:                 double x = 50;
      19:                 double y = 50;
      20:                 child.Arrange(new Rect(new Point(x,y),child.DesiredSize));
      21:             }
      22:             return finalSize;
      23:         }
      24:      }

    这里的PlotPanel类如果有子控件的话,他就会去测量和安排子控件的空间大小。

    假如我们给PlotPanel一个子控件为Button,它想要一个宽度和高度为50的大小。

    PlotPanel先会调用MeasureOverride方法,然后会传给他一个availableSize(可用大小),假如这里的PlotPanel的高度和宽度为400,那么这个availableSize就为(400,400)。

    这里的创建一个size对象( Size size=new Size()),目的是用来返回一个子控件希望的大小(DesiredSize),这时PlotPanel就会foreach子控件,得它DesiredSize这个值。

    根据上面的数据这里的child.DesiredSize应该是(50,50).父控件得到子控件的希望大小后,就要去安排(Arrange)它,也就是在界面上呈现它的大小。

    这时PlotPanel就会去调用ArrangeOverride方法。传入的参数是finalSize(finalRect为Parent最后给你的大小),这里有人会说,子控件已经返回一个希望的大小,为什么还要一个finalSize呢?这里我的理解是,父容器虽然知道了你想要的大小,但你想要的DesiredSize比我给你的availableSize小的话,我还是会给你availableSize大小,也就是这里的 finalSize大小为availableSize,反之给DesiredSize.

    根据上面所说这里我们的finalSize为(400,400)。然后执行child.Arrange();画一个矩形;他的宽和高为(50,50),但还是返回了一个finalSize(400,400).这里真正要看的是child的RenderSize(child实际的大小)。这里的child.RenderSize为(50,50).

    在xaml中。

    <Window x:Class="MeasureAndArrange.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:MeasureAndArrange"
            Title="MainWindow" Height="400" Width="400">
            <my:PlotPanel>
                <Button Width="50" Height="50"/>
            </my:PlotPanel>
    </Window>

    我们运行看看:
    image

    假如,PlotPanel给这个Button一个(30,30)的大小,那会怎么样呢?

    我们修改下代码:

       1:  protected override Size MeasureOverride(Size availableSize)
       2:         {
       3:             foreach (UIElement child in InternalChildren)
       4:             {
       5:                 child.Measure(new Size(30,30));
       6:             }
       7:             return availableSize;
       8:         }

    运行过程:

    availableSize=(400,400)

    finalSize=(400,400)

    child.DesiredSize=(50,50)

    child.RenderSize=(30,30)

    效果图:

    image

    很明显,Button被clip了.

    父和子的MeasureOverride 和ArrangeOverride

    我们先新建两个类MyPanelParent和MyPanel。

    先看代码:

    父类

       1:  public class MyPanelParent:Panel
       2:      {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             foreach (UIElement child in InternalChildren)
       6:             {
       7:                 child.Measure(new Size(120,120));
       8:             }
       9:             return availableSize;
      10:         }
      11:   
      12:         protected override Size ArrangeOverride(Size finalSize)
      13:         {
      14:             double x = 0;
      15:             foreach (UIElement child in InternalChildren)
      16:             {
      17:                 child.Arrange(new Rect(x,0,100,100));
      18:                 x += 100;
      19:             }
      20:             return finalSize;
      21:         }
      22:      }

    子类

       1:   public class MyPanel:Panel
       2:     {
       3:         protected override Size MeasureOverride(Size availableSize)
       4:         {
       5:             foreach (UIElement child in InternalChildren)
       6:             {
       7:                 child.Measure(availableSize);
       8:             }
       9:             return new Size(50,50);
      10:         }
      11:   
      12:         protected override Size ArrangeOverride(Size finalSize)
      13:         {
      14:             double x = 0;
      15:             foreach (UIElement child in InternalChildren)
      16:             {
      17:                child.Arrange(new Rect(new Point(x,0),child.DesiredSize));
      18:                 x += child.DesiredSize.Width;
      19:             }
      20:             return new Size(80,80);
      21:         }
      22:     }

    xaml中

       1:  <Window x:Class="MeasureAndArrange.MainWindow"
       2:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       3:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       4:          xmlns:my="clr-namespace:MeasureAndArrange"
       5:          Title="MainWindow" Height="600" Width="600">
       6:      <Grid>
       7:          <Canvas>
       8:              <my:MyPanelParent Height="400" Width="400" Background="Linen" Canvas.Left="10" Canvas.Top="10">
       9:                  <my:MyPanel  Background="Red" />
      10:                  <my:MyPanel  Background="Red" />
      11:              </my:MyPanelParent>
      12:          </Canvas>
      13:      </Grid>
      14:  </Window>

    这里的大概流程是首先MyPanelParent执行MeasureOverride方法,当执行到 child.Measure时,就会去调用MyPanel的MeasureOverride方法。

    通过递归一个一个实现测量。

    然后MyPanelParent执行ArrangeOverride方法,同样执行到child.Arrange时,调用MyPanel的ArrangeOverride方法。

    下面分析下运行过程:

    Measure

    首先MyPanelParent的MeasureOverride方法传进来一个availableSize大小为(400,400),因为我们在xaml中设置了这个可用大小。

    然后测量给MyPanel一个大小为(120,120),从这里可以看出child.Measure(new Size(120,120));于是调用MyPanel的MeasureOverride(Size availableSize)

    availableSize为(120,120).而MyPanel返回了一个DesireSize为(50,50)给MyPanelParent。

    Arrange

    MyPanelParent这时传进了一个finalSize(400,400),这个大小也就是MyPanelParent的availableSize,然后给MyPanel安排一个矩形宽高为(100,100)。

    这时调用MyPanel的ArrangeOverride传入的finalSize(100,100),这个finalSize就是MyPanelParent对child安排的(Arrange)大小。而这里MyPanel它说,

    它只要呈现(80,80)的Size。这个大小在MyPanelParent给他的finalSize大小之内,所以最后的RenderSize为(80,80).

    图:

    imageimage

    image

    这里主要参考MSDN和其他人的blogs.

  • 相关阅读:
    数据结构与算法之“图”
    数据结构与算法之队列、栈
    数据结构与算法之二叉搜索树
    ue mobile GI
    ue ios 用xcode 断点debug手机 显示call stack的环境搭建 /instrument 显示线程名/stat filestart
    ue 后效里宏的设置
    ue上 sceneColorMobile 在android 和ios上表现不同的问题
    减少ue编译shader的时间
    ue 搭建android/ios联机 debug环境
    对曝光的理解 autoExposure
  • 原文地址:https://www.cnblogs.com/dingli/p/2024786.html
Copyright © 2011-2022 走看看