Wpf 防止RowHeight=Auto拉伸我的网格?

Wpf 防止RowHeight=Auto拉伸我的网格?,wpf,grid,autosize,Wpf,Grid,Autosize,在我的场景中,最终用户通过将其用户界面拆分为多行并定义这些行的高度规则(固定、填充空间、适合内容)来自定义其用户界面。我使用WPF网格实现了这一点 网格开始填满整个屏幕,并且不应该变得更大-用户必须能够随时看到整个网格(行内的滚动条可以,但不是整个网格的滚动条) 问题的症结在于:当用户创建一个或多个“自动”大小的行时,这些行中的内容可能会迫使整个网格的大小扩展,从而引入滚动条,即使我已将网格的最大高度设置为固定数字 当涉及星号大小的行时,情况会变得更糟,因为一旦网格稍微拉伸,星号大小的行就会填满

在我的场景中,最终用户通过将其用户界面拆分为多行并定义这些行的高度规则(固定、填充空间、适合内容)来自定义其用户界面。我使用WPF网格实现了这一点

网格开始填满整个屏幕,并且不应该变得更大-用户必须能够随时看到整个网格(行内的滚动条可以,但不是整个网格的滚动条)

问题的症结在于:当用户创建一个或多个“自动”大小的行时,这些行中的内容可能会迫使整个网格的大小扩展,从而引入滚动条,即使我已将网格的最大高度设置为固定数字

当涉及星号大小的行时,情况会变得更糟,因为一旦网格稍微拉伸,星号大小的行就会填满可用空间,因此即使自动大小的行稍后收缩,网格也会永久拉伸

我需要找到一种方法来限制“自动”行,以便它们根据需要进行扩展和收缩,但所有行的总实际高度永远不会大于整个网格

举例来说,我有一个固定最大高度的网格,以及表示所有大小模式的行

<Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="200"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <TextBlock>
        abc<LineBreak/>
        abc<LineBreak/>
        abc<LineBreak/>
        abc<LineBreak/>
        abc<LineBreak/>                    
    </TextBlock>
</ScrollViewer>


abc
abc
abc
abc
abc


在本例中,随着“abc”文本块的展开,栅格的总高度将超出固定的“300”最大高度。如何防止这种行为以保证网格的最大高度,同时保持自动调整行大小的灵活性?

好的,我发现我必须对网格进行子类化,以便覆盖Measure()和Arrange()布局步骤

我并不认为这是一个伟大的通用解决方案,但它适用于我的场景。请特别注意,我没有处理列,因为在我的例子中,只有一个列。我也没有在单元格中定位元素(我将它们定位在左上角)

如果你需要一个更普遍的解决方案,我认为这是一个很好的开始。列问题与行问题相同,只是方向相反

class NoStretchGrid:Grid
{
    //this override determines what size we ask to be
    //gotta make sure we never ask for more than the max height
    protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
    {
        //what would a basic Grid do?
        System.Windows.Size desiredSize = base.MeasureOverride(constraint);

        if (desiredSize.Height > constraint.Height)
            desiredSize.Height = constraint.Height;

        //if max height is defined and desired height is too big, reduce it
        if (this.MaxHeight != double.NaN && desiredSize.Height > this.MaxHeight)
        {
            desiredSize.Height = this.MaxHeight;
        }

        return desiredSize;
    }

    //this override tells child controls how big they can be and where they're positioned
    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
    {
        //must decide how tall each row will be
        double[] desiredHeights = new double[this.RowDefinitions.Count];
        double[] minimumHeights = new double[this.RowDefinitions.Count];
        double[] finalHeights = new double[this.RowDefinitions.Count];

        //first, find out how tall each row wants to be

        //check for fixed-size rows
        for (int i = 0; i < desiredHeights.Length; i++)
        {
            if (this.RowDefinitions[i].Height.IsAbsolute)
            {
                desiredHeights[i] = this.RowDefinitions[i].Height.Value;
            }
            else
            {
                desiredHeights[i] = 0;
            }

            minimumHeights[i] = this.RowDefinitions[i].MinHeight;
        }

        //then ask children how big they want to be
        foreach (UIElement child in this.InternalChildren)
        {
            int row = Grid.GetRow(child);
            if (!this.RowDefinitions[row].Height.IsAbsolute && child.DesiredSize.Height > desiredHeights[row])
            {
                desiredHeights[row] = child.DesiredSize.Height;
            }

            if ((child as FrameworkElement).MinHeight > minimumHeights[row])
            {
                minimumHeights[row] = (child as FrameworkElement).MinHeight;
            }
        }

        double availableHeight = arrangeSize.Height;

        //reserve minimum heights
        for (int i = 0; i < minimumHeights.Length; i++)
        {
            finalHeights[i] = minimumHeights[i];
            availableHeight -= finalHeights[i];
        }            

        //allow fixed-height rows their height - if some ignoramus made fixed-heights too big, we can't help him
        for (int i = 0; i < desiredHeights.Length; i++)
        {
            if (this.RowDefinitions[i].Height.IsAbsolute)
            {
                finalHeights[i] = this.RowDefinitions[i].Height.Value;
                availableHeight = availableHeight + minimumHeights[i] - finalHeights[i];
            }
        }

        //allow auto-size rows their desired heights, so long as there's height left to be had
        for (int i = 0; i < desiredHeights.Length; i++)
        {                
            if (this.RowDefinitions[i].Height.IsAuto)
            {
                double desiredHeightIncrease = desiredHeights[i] - minimumHeights[i];

                if (desiredHeightIncrease <= availableHeight)
                {
                    finalHeights[i] += desiredHeightIncrease;
                    availableHeight -= desiredHeightIncrease;
                }
                else
                {
                    finalHeights[i] = minimumHeights[i] + availableHeight;
                    availableHeight = 0;
                }
            }
        }

        //now that auto-size rows have been prevented from getting out of control, make the min heights of any star-size rows available again
        for (int i = 0; i < desiredHeights.Length; i++)
        {
            if (this.RowDefinitions[i].Height.IsStar)
            {
                availableHeight += minimumHeights[i];
            }
        }

        //divide any leftover available height proportionally amongst the star-sized rows, while there's height left to be had
        double totalStarValues = 0;
        for (int i = 0; i < desiredHeights.Length; i++)
        {
            if (this.RowDefinitions[i].Height.IsStar)
            {
                totalStarValues += this.RowDefinitions[i].Height.Value;
            }
        }

        for (int i = 0; i < desiredHeights.Length; i++)
        {
            if (this.RowDefinitions[i].Height.IsStar)
            {
                finalHeights[i] = availableHeight * (this.RowDefinitions[i].Height.Value / totalStarValues);
            }
        }

        //decide the vertical position of each row
        double[] rowPositions = new double[desiredHeights.Length];
        rowPositions[0] = 0;
        for (int i = 1; i < rowPositions.Length; i++)
        {
            rowPositions[i] = rowPositions[i - 1] + finalHeights[i - 1];
        }

        //tell children to lay themselves out based on these results
        foreach (UIElement child in this.InternalChildren)
        {
            int row = Grid.GetRow(child);

            //special case for scrollviewer, which doesn't size itself appropriately
            if (child is ScrollViewer)
            {
                ScrollViewer scrollViewer = child as ScrollViewer;

                //temporarily update its height value, JUST for the Arrange() call
                double oldHeight = scrollViewer.Height;
                scrollViewer.Height = finalHeights[row];
                child.Arrange(new Rect(0, rowPositions[row], arrangeSize.Width, finalHeights[row]));

                //restore the original value
                scrollViewer.Height = oldHeight;
            }

            //typical case for non-scroll-viewers
            else
            {
                child.Arrange(new Rect(0, rowPositions[row], arrangeSize.Width, finalHeights[row]));
            }
        }

        return arrangeSize;
    }
}
classnostretchgrid:Grid
{
//此覆盖决定了我们要求的大小
//要确保我们的要求永远不会超过最大高度
受保护的覆盖System.Windows.Size MeasureOverride(System.Windows.Size约束)
{
//基本网格会做什么?
System.Windows.Size desiredSize=base.MeasureOverride(约束);
if(desiredSize.Height>constraint.Height)
desiredSize.Height=约束.Height;
//如果定义了“最大高度”,并且所需高度太大,请将其减小
if(this.MaxHeight!=double.NaN&&desiredSize.Height>this.MaxHeight)
{
desiredSize.Height=此.MaxHeight;
}
返回所需大小;
}
//这个覆盖告诉子控件它们可以有多大以及它们的位置
受保护的覆盖System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
//必须决定每行的高度
double[]desiredHeights=新的double[this.RowDefinitions.Count];
double[]minimumHeights=新的double[this.RowDefinitions.Count];
double[]finalHeights=新的double[this.RowDefinitions.Count];
//首先,找出每一排想要多高
//检查固定大小的行
for(int i=0;idesiredHeights[row])
{
desiredHeights[行]=child.DesiredSize.Height;
}
if((作为框架元素的子元素).MinHeight>minimumheight[行])
{
最小高度[行]=(子元素作为框架元素)。最小高度;
}
}
双可用高度=arrangeSize.Height;
//保留最低高度
对于(int i=0;i<local:NoStretchGrid VerticalAlignment="Stretch">

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="2*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="50"/>
    </Grid.RowDefinitions>

    <ScrollViewer VerticalScrollBarVisibility="Visible" MinHeight="50">
        <Rectangle Fill="Orange" Height="250"/>
    </ScrollViewer>

    <ScrollViewer VerticalScrollBarVisibility="Visible" Grid.Row="1" MinHeight="50">
        <Rectangle Fill="Blue" Height="200"/>
    </ScrollViewer>

    <Grid Background="Pink" Grid.Row="2" MinHeight="30"/>
    <Grid Background="Green" Grid.Row="3" MinHeight="30"/>
    <Grid Background="Red" Grid.Row="4"/>

</local:NoStretchGrid>