1

我希望控件的边界调整大小以适合其所有动态内容,这会改变每一帧。换句话说,如果我通过任何方式(画布、边框等)在控件上显示一个边界框,该框应该包含所有可见内容,其中可见内容的左上角是盒子。一切都应该包含在盒子里。

内容的特殊之处在于它们每帧都会更改,并且根据来自外部源的参数在各处绘制。我将控件的当前高度和宽度设置为“自动” - 这在确保显示所有内容方面效果很好 - 但不幸的是,控件的左上角值将不对应于所有的左上角可见的内容。

是否有一种简单的方法可以使控件的边界更改以包含其所有内容?正如我上面所说,如果我显示一个边界框,该框应该只包含所有可见内容。

4

1 回答 1

2

您没有说如何定位控件的子元素,但子元素是相对于控件的,因此您需要控件缩小其空白左侧和顶部区域,然后移动控件本身,以便所有内容都保持在您放置的位置. 一种方法是编写一个类似于Canvas.

这是一个原型BoundingCanvas,它试图将其位置和大小限制在其子项的范围内:

public class BoundingCanvas : Panel
{
    public BoundingCanvas()
    {
        HorizontalAlignment = HorizontalAlignment.Left;
        VerticalAlignment = VerticalAlignment.Top;
    }

    private Vector minTopLeft;

    protected override Size MeasureOverride(Size availableSize)
    {
        var resultSize = new Size();
        minTopLeft = new Vector(double.PositiveInfinity, double.PositiveInfinity);
        var unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
        foreach (UIElement child in Children)
        {
            child.Measure(unlimitedSize);
            var topLeft = GetTopLeft(child);
            minTopLeft.X = Math.Min(minTopLeft.X, topLeft.X);
            minTopLeft.Y = Math.Min(minTopLeft.Y, topLeft.Y);
            resultSize.Width = Math.Max(resultSize.Width, topLeft.X + child.DesiredSize.Width);
            resultSize.Height = Math.Max(resultSize.Height, topLeft.Y + child.DesiredSize.Height);
        }
        resultSize.Width -= minTopLeft.X;
        resultSize.Height -= minTopLeft.Y;
        return resultSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        Margin = new Thickness(minTopLeft.X, minTopLeft.Y, 0, 0);
        foreach (UIElement child in Children)
            child.Arrange(new Rect(GetTopLeft(child) - minTopLeft, child.DesiredSize));
        return finalSize;
    }

    private Point GetTopLeft(UIElement element)
    {
        return new Point(Canvas.GetLeft(element), Canvas.GetTop(element));
    }
}

你可以像这样使用它:

<Grid>
    <local:BoundingCanvas Background="Pink">
        <Rectangle Canvas.Top="10" Canvas.Left="10" Width="10" Height="10" Fill="DarkRed"/>
        <Rectangle Canvas.Top="20" Canvas.Left="20" Width="10" Height="10" Fill="DarkRed"/>
    </local:BoundingCanvas>
</Grid>

原型需要更多的错误检查和特殊情况处理,但它展示了这个概念。在此示例中,面板使用额外的边距补偿调整后的大小,但您也可以操作Canvas.TopCanvas.Left如果预期的父级是Canvas.

于 2011-02-12T05:07:20.273 回答