控制界限变化的简单方法适合动态内容?

时间:2011-02-12 01:16:21

标签: wpf wpf-controls bounds

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

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

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

1 个答案:

答案 0 :(得分: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.Top,您还可以操纵Canvas.LeftCanvas