Wpf 防止RowHeight=Auto拉伸我的网格?
在我的场景中,最终用户通过将其用户界面拆分为多行并定义这些行的高度规则(固定、填充空间、适合内容)来自定义其用户界面。我使用WPF网格实现了这一点 网格开始填满整个屏幕,并且不应该变得更大-用户必须能够随时看到整个网格(行内的滚动条可以,但不是整个网格的滚动条) 问题的症结在于:当用户创建一个或多个“自动”大小的行时,这些行中的内容可能会迫使整个网格的大小扩展,从而引入滚动条,即使我已将网格的最大高度设置为固定数字 当涉及星号大小的行时,情况会变得更糟,因为一旦网格稍微拉伸,星号大小的行就会填满可用空间,因此即使自动大小的行稍后收缩,网格也会永久拉伸 我需要找到一种方法来限制“自动”行,以便它们根据需要进行扩展和收缩,但所有行的总实际高度永远不会大于整个网格 举例来说,我有一个固定最大高度的网格,以及表示所有大小模式的行Wpf 防止RowHeight=Auto拉伸我的网格?,wpf,grid,autosize,Wpf,Grid,Autosize,在我的场景中,最终用户通过将其用户界面拆分为多行并定义这些行的高度规则(固定、填充空间、适合内容)来自定义其用户界面。我使用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>