【问题标题】:How to exclude child from layouting如何从布局中排除孩子
【发布时间】:2018-07-16 19:26:02
【问题描述】:

看例子:

<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。


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

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

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


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

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

我问的有意义吗?也许自定义容器是这样的?还是我错过了一些现有的和明显的东西?

【问题讨论】:

    标签: c# wpf layout


    【解决方案1】:

    如果您想将Path 限制为所描述几何的大小,只需在Viewbox 上设置StretchDirection="DownOnly"

    如果您真的希望它不请求自己的垂直空间,并且其高度由其布局“邻居”(在本例中为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、或Both。随意扩展它:)。

    实例:

    <Grid VerticalAlignment="Top" Background="Yellow">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>
    
      <TextBlock x:Name="textBlock" />
    
      <t:ZeroHeightDecorator Grid.Column="1">
        <Button>
          <Viewbox>
            <Path Fill="Black" Data="M 0,0 H 100 V 100 H 0 Z" />
          </Viewbox>
        </Button>
      </t:ZeroHeightDecorator>
    </Grid>
    

    【讨论】:

      猜你喜欢
      • 2011-05-03
      • 2012-11-05
      • 1970-01-01
      • 2019-01-04
      • 1970-01-01
      • 2013-01-08
      • 1970-01-01
      • 2021-09-10
      • 2016-09-30
      相关资源
      最近更新 更多