如何从布局中排除儿童

时间:2018-02-06 16:46:45

标签: c# wpf layout

看一下例子:

<Grid VerticalAlignment="Top" Background="Yellow">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="auto" />
    </Grid.ColumnDefinitions>

    <TextBlock x:Name="textBlock"/>

    <Button Grid.Column="1">
        <Viewbox>
            <Path Height="100" Width="100" Fill="Black" Data="M 0,0 H 100 V 100 H 0 Z" />
        </Viewbox>
    </Button>
</Grid>

这是一个带矢量图形的按钮,我希望它尽可能小(限制来自爆炸的矢量图形)。

以下是它的样子以及我希望它如何:

有几种可能的解决方案如何克服问题,列举一些:

  1. 通过将Width / Height绑定到其他元素(这与设计师有问题):

    ...
    <Button Height="{Binding ActualHeight, ElementName=textBlock}" ...>
    ...
    

    这通常与 ghost 一起使用:其他人使用的特殊隐形元素(与它没有关系)来布局自己。

  2. 通过在Canvas魔法容器)中托管元素,但Canvas本身需要布局。

    您可以尝试将Button放入Canvas。这将导致父Grid仅取TextBlock的高度,但是还有另一个问题:如何定位(布局)Canvas本身,以便其子项布局正确,kek。< / p>

  3. 在上面的示例中,我实际上并不希望TextBlock成为Button姐妹,它们可能重叠(您不会想要按钮)要隐藏,如果可用的大小不够,它应该重叠一些不太重要的东西),我只是希望它们有相同的父级(如果它移动 - 孩子会移动)。困惑?看这里:

    <Grid>
        <TextBlock ... />
        <Button HorizontalAlignment="Right" ... />
    </Grid>
    

    这种布局有同样的问题,可以类似地解决。

    现在尝试从上面的具体例子中抽象出来。

    实际想要的是:了解如何从容器布局中排除元素。就像元素被折叠一样,所以父容器将测量子大小(除了这个元素),布局子元素然后,在布局完成后,元素突然变得可见并受父容器限制,同时可以使用各种对齐。

    我要问的是否有意义?也许自定义容器是这样的?或者我是否会错过现有的和明显的东西?

1 个答案:

答案 0 :(得分:1)

如果您想将Path约束所描述几何体的大小,就像在StretchDirection="DownOnly"上设置Viewbox一样简单。

如果真正希望它不要求自己的垂直空间,并且其高度由其布局“邻居”(在本例中为TextBlock)决定,那么你我需要将它包装在自定义布局容器中。但是你不能简单地从布局中排除 - 至少不完全。如果你这样做,元素总是会以零宽度和高度结束。相反,您可以在两次传递中测量,第一次传递请求子高度为零,第二次传递基于第一次传递后给出的排列大小所需的大小。

认为下面的容器会给你你想要的东西,但会被警告我没有彻底测试过它。使用风险自负。

public class ZeroHeightDecorator : Border
{
    private Size _lastSize;
    private Size _idealSize;

    protected override void OnVisualChildrenChanged(DependencyObject added, DependencyObject removed)
    {
        base.OnVisualChildrenChanged(added, removed);
        _idealSize = new Size();
        _lastSize = new Size();
    }

    protected override Size MeasureOverride(Size constraint)
    {
        var child = this.Child;
        if (child == null)
            return new Size();
        if (child.IsMeasureValid)
            child.Measure(new Size(Math.Max(_lastSize.Width, constraint.Width), _lastSize.Height));
        else
            child.Measure(new Size(constraint.Width, 0d));
        _idealSize = child.DesiredSize;
        return new Size(_idealSize.Width, 0d);
    }

    protected override Size ArrangeOverride(Size arrangeSize)
    {
        var child = this.Child;
        if (child != null)
        {
            if (arrangeSize != _lastSize)
            {
                // Our parent will assume our measure is the same if the last
                // arrange bounds are still available, so force a reevaluation.
                this.InvalidateMeasure();
            }
            child.Arrange(new Rect(arrangeSize));
        }
        _lastSize = arrangeSize;
        return arrangeSize;
    }
}

更灵活的容器允许您指定最小化的维度:WidthHeightNeither或{{1 }}。随意扩展它:)。

行动中的例子:

Both

Screenshot