【问题标题】:How to balance contrls using ArrangeOverride and MeasureOverride如何使用 ArrangeOverride 和 MeasureOverride 平衡控制
【发布时间】:2021-10-01 09:50:20
【问题描述】:

我创建了一个自定义面板来帮助理解 MeasureOverride 和 ArrangeOverride 方法。我希望奇数项显示在左侧,偶数项显示在右侧。

1 - 0
3 - 2
5 - 3
7 - 4
    8
public class MyPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var mySize = new Size();
        foreach (UIElement child in this.InternalChildren)
        {
            child.Measure(availableSize);
            mySize.Width =  child.DesiredSize.Width * 2;
            var itemCount = Math.Ceiling(InternalChildren.Count / 2f);
            mySize.Height = itemCount  * child.DesiredSize.Height;
        }
        return mySize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        var odd = InternalChildren.OfType<UIElement>()
            .Where((c, i) => i % 2 != 0);
        var even = InternalChildren.OfType<UIElement>()
            .Where((c, i) => i % 2 == 0);

        var location = new Point();

        foreach (var child in even)
        {
            child.Arrange(new Rect(location, child.DesiredSize));
            location.X = child.DesiredSize.Width;
            location.Y += child.DesiredSize.Height;
            Debug.WriteLine(location);
        }
        
        location = new Point();
        foreach (var child in odd)
        {
            child.Arrange(new Rect(location, child.DesiredSize));
            location.Y += child.DesiredSize.Height;
            Debug.WriteLine(location);
        }

        return finalSize;
    }
}

这是面板的标记。

<Canvas>
    <local:MyPanel x:Name="MyPanel1" Canvas.Left="500" Canvas.Top="200" 
       Background="#FFE84B4B">
    <Button Content="0"></Button>
    <Button Content="1"></Button>
    <Button Content="2"></Button>
    <Button Content="3"></Button>
    <Button Content="4"></Button>
    <Button Content="5"></Button>
    <Button Content="6"></Button>
    <Button Content="7"></Button>
    <Button Content="8"></Button>
</local:MyPanel>
</Canvas>

这是结果

如何让项目 0 显示并与 1 列对齐?

【问题讨论】:

  • item0 正好在 item1 之下,因为您在安排 item child.Arrange(new Rect(location, child.DesiredSize)); location.X = child.DesiredSize.Width; 后分配 location.X。在循环之前设置 X 一次。但它只有在所有项目都具有相同大小时才有效,但情况并非总是如此
  • child.Arrange(new Rect(location, child.DesiredSize));的第一次调用中location.X的值显然是0。
  • 设置location.X = child.DesiredSize.Width; 完全没有意义,因为X 是由child 左边的item 或左边所有item 的宽度决定的。
  • 您也可以使用具有两列和 FlowDirection RightToLeft 的 UniformGrid 来实现此目的。
  • 如前所述,无论如何都是错误的。它是偶然起作用的,因为所有项目似乎都具有相同的宽度。

标签: wpf xaml user-interface custom-controls blend


【解决方案1】:

我首先将项目安排在左侧(“赔率”),因为它们定义了水平偏移。然后将该偏移量用于“偶数”。
当然,这只是一种演示代码。 DesiredSize 不是 RenderSize。一旦 DP 系统计算出两者之间的差异,固定定位证明就太僵硬了。

    protected override Size ArrangeOverride(Size finalSize)
    {
        var odd = InternalChildren.OfType<UIElement>()
                                  .Where((c, i) => i % 2 != 0);
        var even = InternalChildren.OfType<UIElement>()
                                   .Where((c, i) => i % 2 == 0);

        var location       = new Point();
        foreach (var child in odd)
        {
            child.Arrange(new Rect(location, child.DesiredSize));
            location.Y += child.DesiredSize.Height;
            Debug.WriteLine(location);
        }

        var evenHorzOffset = odd.First().DesiredSize.Width;
        location = new Point(evenHorzOffset, 0);

        foreach (var child in even)
        {
            child.Arrange(new Rect(location, child.DesiredSize));
            location.Y += child.DesiredSize.Height;
            Debug.WriteLine(location);
        }

        return finalSize;
    }

【讨论】:

    猜你喜欢
    • 2014-08-23
    • 2012-02-01
    • 2013-11-09
    • 2011-01-25
    • 2021-06-23
    • 2011-02-04
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多