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

使WPF/SL网格在确定大小时忽略子元素,wpf,silverlight,layout,grid,Wpf,Silverlight,Layout,Grid,我有一个网格,它有几个孩子,其中一个是ScrollViewer。我希望网格根据其所有子项调整自身大小,但ScrollViewer除外,我只想占用通过调整网格大小为其其余子项创建的空间。(例如,网格为2x2,ScrollViewer位于第0行第0列,因此其他三个网格条目足以确定网格的尺寸。) 有什么好办法吗?我已经考虑过创建一个自定义面板来替换网格或包含ScrollViewer,但在MeasureOverride/ArrangeOverride调用期间,我从未接到过一个可以告诉我我关心的网格行/列

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

有什么好办法吗?我已经考虑过创建一个自定义面板来替换网格或包含ScrollViewer,但在MeasureOverride/ArrangeOverride调用期间,我从未接到过一个可以告诉我我关心的网格行/列(例如,第0行,第0列)的最终宽度/高度的调用

我的一个想法是从网格派生并调用基本的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>

我希望网格的大小不会随着ScrollViewer中按钮的大小改变而改变,例如,我希望网格为ScrollViewer提供100x100的正方形,该正方形由网格的其余内容决定。如果我将3个100x100按钮中的每一个都更改为200x200,我希望ScrollViewer获得200x200,等等

Pavlo的示例是迄今为止最接近的,网格行/列的大小适当,但ScrollViewer不适应调用Arrange时给定的大小。见下文:


如果我正确理解了您的需求,那么您可以执行以下技巧。创建一个装饰器,该装饰器将在测量阶段请求0个空间,并在排列阶段使用所有给定的空间排列子对象:

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>

帕夫洛·格拉兹科夫的回答对我来说非常有效!我将其用于不希望指定显式大小的控件。。。我添加了一些逻辑和属性来击败一维:

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);
        }
    }
公共密封类装饰器
:装饰师
{
/// 
///设置是否覆盖宽度。
/// 
公共静态只读从属属性DisableWidthOverrideProperty
=DependencyProperty.寄存器(
名称(NoSizeDecorator.DisableWidthOverride),
类型(bool),
类型(NoSizeDecorator),
新框架属性元数据(
假,,
FrameworkPropertyMetadataOptions.AffectsMeasure));
/// 
///设置是否覆盖宽度。
/// 
公共布尔禁用宽度覆盖
{
get=>(bool)GetValue(NoSizeDecorator.DisableWidthOverrideProperty);
set=>SetValue(NoSizeDecorator.DisableWidthOverrideProperty,value);
}
/// 
///设置是否覆盖高度。
/// 
公共静态只读从属属性DisableHeightOverrideProperty
=DependencyProperty.寄存器(
名称(NoSizeDecorator.DisableHeightOverride),
类型(bool),
类型(NoSizeDecorator),
新框架属性元数据(
假,,
FrameworkPropertyMetadataOptions.AffectsMeasure));
/// 
///设置是否覆盖高度。
/// 
公共布尔禁用高度覆盖
{
get=>(bool)GetValue(NoSizeDecorator.DisableHeightOverrideProperty);
set=>SetValue(NoSizeDecorator.disableheightoverrideeproperty,value);
}
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
UIElement child=child;
if(child==null)
返回新的大小();
约束
=新尺寸(
禁用宽度覆盖
?限制。宽度
:0D,
禁用高度覆盖
?限制。高度
:0D);
儿童。测量(约束);
返回新尺寸(
禁用宽度覆盖
?child.DesiredSize.Width
:0D,
禁用高度覆盖
?儿童、理想尺寸、身高
:0D);
}
}

请提供一个XAML示例,很难准确理解您需要什么。当然,这一点很好。我刚刚添加了一个。小问题:Silverlight中没有Decorator类。例如,边框从Silverlight中的FrameworkElement派生。WPF增加了Decorator类。谢谢Pavlo。这是接近我所尝试的,但肯定更接近我想要的结果。我继续在WPF中进行了尝试(认为我可以稍后适应SL),问题是,尽管网格行和列的大小现在已适当调整,但ScrollViewer及其内容仍然占据了它们想要的空间,即使它们被ArrangeOverride以100x100的边界命中。我在上面添加了一张图片来说明我的意思。是的,有一个错误。我们也必须用0空间测量孩子。更新了代码。我已经用WPF测试过了,而且