Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 制作控件的简单方法';s边界更改以适应动态内容?_Wpf_Wpf Controls_Bounds - Fatal编程技术网

Wpf 制作控件的简单方法';s边界更改以适应动态内容?

Wpf 制作控件的简单方法';s边界更改以适应动态内容?,wpf,wpf-controls,bounds,Wpf,Wpf Controls,Bounds,我想要一个控件的边界调整大小,以适应它的所有动态内容,这会改变每一帧。换句话说,如果我通过任何方式(画布、边框等)在控件上显示边界框,则该框应包含所有可见内容,其中可见内容的左上角是框的左上角。所有东西都应该放在盒子里 内容的特殊之处在于,它们会更改每一帧,并根据外部源的参数绘制整个位置。我将控件的当前高度和宽度设置为“自动”-这可以很好地确保显示所有内容-但不幸的是,控件的左上角值不会对应于所有可见内容的左上角 是否有一种简单的方法使控件的边界更改为包含其所有内容?如上所述,如果我显示一个边界

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

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


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

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

下面是一个原型
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
,您也可以操作
Canvas.Top
Canvas.Left
,我感谢您的回答。为什么要执行子.Measure(未限制大小)
?我不太确定我是否理解度量的作用,即使在阅读了文档之后。另外,在您的
GetTopLeft
函数中,如何获得使用边距定位的渲染转换或布局转换元素的左上角位置?我让我的BoundedCanvas像一个真实的画布一样运行,它会询问其子代“您有多大,顺便说一句,您可以达到您想要的大小”。对于margin,您可以使用它来代替Canvas.Top和Canvas.Left,也可以将其添加到Canvas.Top和Canvas.Left中。LayoutTransform将显示在DesiredSize中,您无需特殊处理。由于我们所做的是与布局相关的,所以根据定义不应考虑RenderTransform。很好,非常感谢您的帮助。这给了我一个好主意,我应该从这里做什么。