使用自定义控件时出现Silverlight错误“检测到布局循环,无法完成布局”。

14
我正在使用Silverlight从ContentControl派生出自定义控件,进行一些特殊格式化以在内容后面添加阴影。我已经几乎完成了它,但最近遇到了一个奇怪的错误。如果它包含除Border之外的任何内容,或者具有明确定义的高度和宽度的Grid / Stackpanel等,则可以正常工作。 在IE中,我会得到一个JavaScript错误,文本为:“运行时错误4008 ...检测到布局周期...布局无法完成。” 如果我在包含的Grid / Stackpanel等上指定高度和宽度,则可以正常工作。关于此错误在使用太多文本框(超过250个)时的信息很多,但我可以使用网格中的单个按钮重现我的错误。页面上没有任何文本框。该错误与检测到的无限循环有关。我在代码中设置了一些断点,似乎在渲染期间“SizeChanged”事件被频繁调用,每次高度/宽度增加10。我假设设置默认高度/宽度会使其跳过数字的递增,但我不知道为什么会发生这种错误。是否有人遇到过这种情况,或者有任何想法?

我在使用Telerik RadWindow控件时遇到了这个问题(在普通的ChildWindow中也可能会发生)。当我指定MinHeight和MinWidth而没有指定Width和Height时,问题就出现了。当窗口内容的大小改变时,会发生布局循环。将Width和Height设置为与MinWidth和MinHeight相同的值可以解决问题。 - Richard Beier
5个回答

7

这里有一篇关于此错误的好博客文章

基本上,可能发生的情况是你在MeasureOverride中改变了某些尺寸,导致另一个测量,进而改变了尺寸,又导致了一次测量,如此循环。我之前也碰到过这个问题,并通过删除任何导致布局更新或在布局周期期间触发布局更新的代码来解决它。

更新:由于博客文章已经消失,这里引用它的全部内容:

继续我的Silverlight 2坑点系列,我想谈谈一个常见的错误。这个错误是新东西,您可能会在将代码从Beta 2移动到RC或更高版本时看到。在Beta 2中,如果布局引擎检测到一个循环,它不会抛出任何错误;据我所知,布局只是被中止了。但是使用Beta2后的版本,会抛出一个错误。

您将收到的错误将指定“Layout Cycle Detected”作为消息。这个错误信息非常准确--布局引擎在您的布局中检测到一个循环;或者换句话说,您的布局中有一个无限循环。

导致此错误的最大罪魁祸首是LayoutUpdated事件处理程序中的代码。如果您的LayoutUpdated事件处理程序对控件的布局进行任何更改,那么它将导致LayoutUpdated事件再次触发,一遍又一遍...:-)

但有时候您确实需要在此事件处理程序中使用布局更改代码,那该怎么办呢?

首先,您应该考虑是否真的需要在每次调用LayoutUpdated时发生布局更改。是否只需处理Loaded事件以及Application.Current.Host.Content.Resized事件即可。在这两个事件之间,当控件加载到视觉树中时,您将收到通知,并且在主机调整大小时,您将收到通知,这可能会导致您需要再次更改布局。模态对话框等情况应属于此类别。

其次,如果您确实需要使用LayoutUpdated,则可能只需要在布局更改周围放置一些条件。例如,如果您正在计算控件的新宽度和高度,在实际设置宽度和高度之前,请检查当前值是否与您计算的值不同。这将允许第一个LayoutUpdated事件调整控件的大小,从而触发另一个LayoutUpdated事件,但是该事件将识别到没有工作要做,循环将结束。

当您处理SizeChanged事件或对控件的布局进行任何其他重写时,这些相同的规则也适用。


这是我遇到的问题。链接的博客文章建议只在初始加载和Silverlight应用程序(包含用户控件)更改大小时执行布局操作。这对我可能有用,但我还没有在执行动画和其他操作时进行测试。感谢您的帮助! - Matthew Timbs
时光倒流机来拯救:https://web.archive.org/web/20110203182929/http://jeffhandley.com/archive/2008/09/26/silverlight-2-post-beta2-gotcha---layout-cycle-detected.aspx - Bryant

6

常见的原因是处理SizeChanged事件,然后在处理程序中执行影响元素大小的操作。有时这不是很明显 - 例如可能修改影响其容器大小的子元素。


4

1.如果你在ScrollViewer中使用LongListSelector,请最好将其删除。我曾经遇到过同样的问题,我的LongListSelector就在ScrollViewer中。在ItemRealized事件期间,会出现这个错误。

2.不要在itemrealized内部使用updatelayout()..我曾经使用过类似的东西

 list.UpdateLayout();
 list.ScrollTo(e.Container.Content);

只需使用ScrollTo即可。

3.如果您在LongListSelector中使用图像,请确保设置图像的高度和宽度。


1

我曾经遇到过同样的问题,我的解决方法是将所有布局更新(大小更改)放在一个“调用”委托中,并稍后调用它。这样可以防止崩溃,但有可能会陷入循环。


0

我曾经遇到过同样的问题,但它只极少数情况下发生。我的代码多年来一直没有改变,最近有人才遇到了这个问题。

我在 LongListSelector 数据源中放置了一个 TextBlock,并将其字体大小设置为 21。将字体大小更改为任何其他值即可解决我的问题...

我的 LongListSelectors 在 ScrollViewer 中。

            <phone:PanoramaItem x:Name="OwnedGamesPanoramaItem" >
            <ScrollViewer Margin="5,-25,0,0">
            <StackPanel>
                    <TextBlock toolkit:TiltEffect.IsTiltEnabled="True" Text="{Binding Path=LocalizedResources.XOwnedGames, Source={StaticResource LocalizedStrings}}" FontFamily="Segoe WP Semibold" CharacterSpacing="10"  FontSize="25" Margin="0,10,0,25" TextWrapping="Wrap"/>
                    <TextBlock x:Name="ownedGameLoadingTextBox" Margin="10" FontSize="26" Text="{Binding Path=LocalizedResources.XLoading, Source={StaticResource LocalizedStrings}}" HorizontalAlignment="Center"/>
                    <phone:LongListSelector x:Name="OwnedGameListBox" Tap="OwnedGameListBoxTap" ScrollViewer.VerticalScrollBarVisibility="Disabled" ItemRealized="OwnedGameListBox_ItemRealized" ItemUnrealized="OwnedGameListBox_ItemUnrealized" BorderThickness="0,20,0,0"  >
                        <phone:LongListSelector.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Vertical" Tap="OwnedGameListBoxTap" Margin="0,0,0,12">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" Tap="StackPanel_Tap_1">
                                        <Image Width="60" Source="{Binding getSmallImageActualURL}" Height="60"  Margin="3" VerticalAlignment="Top" />
                                        <StackPanel Margin="15,0,0,0">
                                            <TextBlock Width="320" TextWrapping="Wrap" Text="{Binding name}" Margin="0,0,0,0" FontSize="32" />
                                            <TextBlock Text="{Binding getTotalPlaytimeFormatted}" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="21" >
                                                <TextBlock.Foreground>
                                                    <SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
                                                </TextBlock.Foreground>
                                            </TextBlock>
                                        </StackPanel>
                                    </StackPanel>
                                </StackPanel>
                            </DataTemplate>
                        </phone:LongListSelector.ItemTemplate>
                    </phone:LongListSelector>
                </StackPanel>
            </ScrollViewer>
        </phone:PanoramaItem>

修复:

<TextBlock Text="{Binding getTotalPlaytimeFormatted}" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="22" >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接