WPF MeasureOverride 循环
WPF MeasureOverride loop
这是背景:
我已经决定删除滚动查看器,并只使用一个会随着基础变化而增加的滚动查看器。
我有一个很奇怪的问题要解决。
是这样的,我有一个项目的设置是这样的。
Parent -> Child。
滚动查看器 -> Canvas。
Canvas -> 网格。
Grid -> 多个Canvases(分为不同的网格列)。
<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
ContextMenu="{StaticResource DesignerCanvasContextMenu}">
<s:DesignerCanvas.Background>
<SolidColorBrush Opacity="0"/>
</s:DesignerCanvas.Background>
<Grid x:Name="MainGrid" Background="#FF61B5B9">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
Background="{StaticResource WindowBackgroundBrush}"
FocusVisualStyle="{x:Null}" Width="700" Height="700"
Margin="5"/>
<!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->
</Grid>
</s:DesignerCanvas>
</ScrollViewer>
我来解释一下,我有一个项目在较低的 canvas 上,假设我想将它从一个 canvas 移到另一个,我设法做到了因为我有更高的职位 canvas 这让我可以。
问题是当我想调整项目大小时,我们假设下方 canvases 之一的项目之一正在向边缘移动,我可以重新调整 canvas,然而,这对上层网格没有影响(有时它会很奇怪),所以我的上层 canvas 没有任何影响,所以我的滚动查看器没有通知大小增加。
如果我手动告诉网格测量自身,因为其中一个元素 child 超过了划分的 canvas 大小,那么它也会告诉所有的 child测量自己以便 return 获得所需的值,这将导致无限循环。
这里是 MeasureOverride 函数:
protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
foreach (UIElement element in this.InternalChildren)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;
//measure desired size for each child
element.Measure(constraint);
Size desiredSize = element.DesiredSize;
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left + desiredSize.Width);
size.Height = Math.Max(size.Height, top + desiredSize.Height);
}
}
// add margin
size.Width += 10;
size.Height += 10;
//Let's assume here I will tell the grid to manually measure itself -> infinite loop
return size;
}
我该如何解决这个问题?我怎样才能通知链中的所有 child 在不引起无限循环的情况下进行自我测量?
我奇怪地解决了这个问题。
我没有再用Width了,改用MinWidth了,所有的计算一下子就固定了。
<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
ContextMenu="{StaticResource DesignerCanvasContextMenu}">
<s:DesignerCanvas.Background>
<SolidColorBrush Opacity="0"/>
</s:DesignerCanvas.Background>
<Grid x:Name="MainGrid" Background="#FF61B5B9">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
Background="{StaticResource WindowBackgroundBrush}"
FocusVisualStyle="{x:Null}" MinWidth="600" MinHeight="600"
Margin="5"/>
<!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->
</Grid>
</s:DesignerCanvas>
</ScrollViewer>
这是背景:
我已经决定删除滚动查看器,并只使用一个会随着基础变化而增加的滚动查看器。
我有一个很奇怪的问题要解决。
是这样的,我有一个项目的设置是这样的。
Parent -> Child。
滚动查看器 -> Canvas。
Canvas -> 网格。
Grid -> 多个Canvases(分为不同的网格列)。
<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
ContextMenu="{StaticResource DesignerCanvasContextMenu}">
<s:DesignerCanvas.Background>
<SolidColorBrush Opacity="0"/>
</s:DesignerCanvas.Background>
<Grid x:Name="MainGrid" Background="#FF61B5B9">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
Background="{StaticResource WindowBackgroundBrush}"
FocusVisualStyle="{x:Null}" Width="700" Height="700"
Margin="5"/>
<!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->
</Grid>
</s:DesignerCanvas>
</ScrollViewer>
我来解释一下,我有一个项目在较低的 canvas 上,假设我想将它从一个 canvas 移到另一个,我设法做到了因为我有更高的职位 canvas 这让我可以。
问题是当我想调整项目大小时,我们假设下方 canvases 之一的项目之一正在向边缘移动,我可以重新调整 canvas,然而,这对上层网格没有影响(有时它会很奇怪),所以我的上层 canvas 没有任何影响,所以我的滚动查看器没有通知大小增加。
如果我手动告诉网格测量自身,因为其中一个元素 child 超过了划分的 canvas 大小,那么它也会告诉所有的 child测量自己以便 return 获得所需的值,这将导致无限循环。
这里是 MeasureOverride 函数:
protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
foreach (UIElement element in this.InternalChildren)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;
//measure desired size for each child
element.Measure(constraint);
Size desiredSize = element.DesiredSize;
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left + desiredSize.Width);
size.Height = Math.Max(size.Height, top + desiredSize.Height);
}
}
// add margin
size.Width += 10;
size.Height += 10;
//Let's assume here I will tell the grid to manually measure itself -> infinite loop
return size;
}
我该如何解决这个问题?我怎样才能通知链中的所有 child 在不引起无限循环的情况下进行自我测量?
我奇怪地解决了这个问题。 我没有再用Width了,改用MinWidth了,所有的计算一下子就固定了。
<ScrollViewer x:Name="MainScrollView" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<s:DesignerCanvas Focusable="true" x:Name="MyDesignerTop"
FocusVisualStyle="{x:Null}" IsHitTestVisible="True"
Grid.ColumnSpan="2147483647" Panel.ZIndex="2147483647"
ContextMenu="{StaticResource DesignerCanvasContextMenu}">
<s:DesignerCanvas.Background>
<SolidColorBrush Opacity="0"/>
</s:DesignerCanvas.Background>
<Grid x:Name="MainGrid" Background="#FF61B5B9">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<s:DesignerCanvas Focusable="true" x:Name="MyDesigner"
Background="{StaticResource WindowBackgroundBrush}"
FocusVisualStyle="{x:Null}" MinWidth="600" MinHeight="600"
Margin="5"/>
<!--ContextMenu="{StaticResource DesignerCanvasContextMenu}"-->
</Grid>
</s:DesignerCanvas>
</ScrollViewer>