在确定大小时,使WPF / SL网格忽略子元素

时间:2011-01-31 17:37:01

标签: wpf silverlight layout grid

我有一个Grid,它有几个孩子,其中一个是ScrollViewer。我希望Grid基于它的所有子除了 ScrollViewer之外的大小,我想要占用通过为其余子节点调整Grid的大小来创建的空间。 (例如,网格为2x2,ScrollViewer位于第0行,第0列,因此其他三个网格条目足以确定网格的尺寸。)

有一个很好的方法吗?我已经研究过创建一个自定义面板来替换网格或包含ScrollViewer,但是在MeasureOverride / ArrangeOverride调用期间我没有得到一个可以告诉我网格行的最终宽度/高度的调用/ column我关心的(例如,第0行,第0列)。

我有一个想法是从Grid派生并调用基础MeasureOverride / ArrangeOverride但是在调用之前从网格的子项中删除ScrollViewer(并在之后将其放回),但在布局计算期间弄乱了可视化树好像是个坏主意。

以下是一个例子:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ScrollViewer Grid.Row="0" Grid.Column="0" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
            <Button Height="300" Width="300"/>
        </ScrollViewer>
        <Button Grid.Row="1" Grid.Column="0" Height="100" Width="100" Content="1,0"/>
        <Button Grid.Row="0" Grid.Column="1" Height="100" Width="100" Content="0,1"/>
        <Button Grid.Row="1" Grid.Column="1" Height="100" Width="100" Content="1,1"/>
    </Grid>
</Grid>

我希望Grid的大小不会随着ScrollViewer中Button的大小的变化而改变 - 例如,我希望Grid为ScrollViewer提供100x100的平方,该平方由Grid的其余内容决定。如果我将3个100x100按钮中的每个按钮更改为200x200,我希望ScrollViewer能够获得200x200等等。

Pavlo的例子让我到目前为止最接近,网格行/列的大小合适,但是当调用Arrange时,ScrollViewer不适应给定的大小。见下文:

Image showing effect of Pavlo's NoSizeDecorator

2 个答案:

答案 0 :(得分:7)

如果我理解你想要什么,那么你可以做以下技巧。在Measure阶段创建一个要求0空间的装饰器,并在Arrange阶段安排具有所有给定空间的子项:

public class NoSizeDecorator : Decorator
{
    protected override Size MeasureOverride(Size constraint) {
        // Ask for no space
        Child.Measure(new Size(0,0));
        return new Size(0, 0);
    }        
}

您的XAML将如下所示:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <my:NoSizeDecorator Grid.Row="0" Grid.Column="0">
            <ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
                <Button Height="300" Width="300" Content="0,0"/>
            </ScrollViewer>
        </my:NoSizeDecorator>

        <Button Grid.Row="1" Grid.Column="0" Height="100" Width="100" Content="1,0"/>
        <Button Grid.Row="0" Grid.Column="1" Height="100" Width="100" Content="0,1"/>
        <Button Grid.Row="1" Grid.Column="1" Height="100" Width="100" Content="1,1"/>
    </Grid>
</Grid>

答案 1 :(得分:1)

Pavlo Glazkov的回答对我很有用!我已经将它用于一个不想指定显式大小的控件...我添加了一些逻辑和属性来打败一个维度:

public sealed class NoSizeDecorator
            : Decorator
    {
        /// <summary>
        /// Sets whether the width will be overridden.
        /// </summary>
        public static readonly DependencyProperty DisableWidthOverrideProperty
                = DependencyProperty.Register(
                        nameof(NoSizeDecorator.DisableWidthOverride),
                        typeof(bool),
                        typeof(NoSizeDecorator),
                        new FrameworkPropertyMetadata(
                                false,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));

        /// <summary>
        /// Sets whether the width will be overridden.
        /// </summary>
        public bool DisableWidthOverride
        {
            get => (bool)GetValue(NoSizeDecorator.DisableWidthOverrideProperty);
            set => SetValue(NoSizeDecorator.DisableWidthOverrideProperty, value);
        }

        /// <summary>
        /// Sets whether the height will be overridden.
        /// </summary>
        public static readonly DependencyProperty DisableHeightOverrideProperty
                = DependencyProperty.Register(
                        nameof(NoSizeDecorator.DisableHeightOverride),
                        typeof(bool),
                        typeof(NoSizeDecorator),
                        new FrameworkPropertyMetadata(
                                false,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));

        /// <summary>
        /// Sets whether the height will be overridden.
        /// </summary>
        public bool DisableHeightOverride
        {
            get => (bool)GetValue(NoSizeDecorator.DisableHeightOverrideProperty);
            set => SetValue(NoSizeDecorator.DisableHeightOverrideProperty, value);
        }


        protected override Size MeasureOverride(Size constraint)
        {
            UIElement child = Child;
            if (child == null)
                return new Size();
            constraint
                    = new Size(
                            DisableWidthOverride
                                    ? constraint.Width
                                    : 0D,
                            DisableHeightOverride
                                    ? constraint.Height
                                    : 0D);
            child.Measure(constraint);
            return new Size(
                    DisableWidthOverride
                            ? child.DesiredSize.Width
                            : 0D,
                    DisableHeightOverride
                            ? child.DesiredSize.Height
                            : 0D);
        }
    }