Silverlight Error "Layout Cycle Detected Layout could not complete" when using custom control
Asked Answered
A

5

14

I'm building a custom control in Silverlight by deriving from ContentControl and doing some special formatting to put a dropshadow behind the contents.

I've nearly got it working but have recently ran into a bizarre error. It works fine if it contains anything besides a Border, or a Grid/Stackpanel/etc that does not have an explicitly defined height and width.

I get a JavaScript error in IE, and the text says:

Runtime Error 4008... Layout Cycle Detected... Layout Could Not Complete.

If I specify a height and width on the contained grid/stackpanel/etc it works fine.

There is a ton on the web about this error when too many textboxes are used (over 250), but I'm able to reproduce my error with a single button in a grid.

I have no textboxes at all on the page. The error has to do with a detected infinite loop. I set a few breakpoints in the code and it seems that the "SizeChanged" event is getting called a lot during rendering, and each time the height/width increments by 10.

I'm assuming that setting a default height/width causes it to skip this incrementing of the number, but I have no idea why this error is happening.

Has anyone ran into this or have any ideas?

Aerostat answered 11/3, 2009 at 20:33 Comment(1)
I've run into this issue with the Telerik RadWindow control (it would probably also happen with the regular ChildWindow). The problem happened when I specified MinHeight and MinWidth without specifying Width and Height. When the size of the window's contents changed, a layout cycle occurred. Setting Width and Height to the same values as MinWidth and MinHeight solved the problem.Desantis
F
7

There is a good blog post on this error here.

Bascially what can happen is you're changing some size in a MeasureOverride somewhere which causes another measure, which changes the size, which causes a measure and so on. I ran into this once before and fixed it by removing any code that caused a layout update or triggered a layout update during the layout cycle.

Update: Since the blog post is gone, quoting it here in full:

Continuing my series of gotchas for Silverlight 2, I wanted to talk about a common error that people are seeing. This error is something new that you might see when moving code from Beta 2 to the Release Candidate or later. In Beta 2, if the layout engine detected a cycle, it didn't throw any errors; as I understand it, the layout was just aborted. But with post Beta2 bits, an error is thrown.

The error you'll get will specify "Layout Cycle Detected" as the message. This error message is very accurate--the layout engine detected a cycle within your layout; or another way to say it, you have an infinite loop in your layout.

The biggest culprit that leads to this error is code within the LayoutUpdated event handler. If your LayoutUpdated event handler does anything to alter the layout of your control, then that will cause the LayoutUpdated event to fire again, and again, and again... :-)

Sometimes you need to have layout altering code within this event handler though, so what is one to do?

First, you should consider whether you really need the layout changes to occur on every call to LayoutUpdated. Would it suffice to handle the Loaded event as well as the Application.Current.Host.Content.Resized event. Between these two events, you'll get notified when the control is loaded into the visual tree, and you'll get notified any time the host is resized, which could cause you to need to change your layout again. Scenarios like modal dialogs should fall into this category.

Second, if you really do need to use LayoutUpdated, you might just need to put some conditions around your layout changes. For instance, if you are calculating a new width and height for your control, before you actually set the width and height, check to make sure the current values differ from what you calculated. This will allow the first LayoutUpdated event to resize your control, which triggers another LayoutUpdated event, but that event will recognize that there's no work to do, and the cycle will end.

These same rules will apply when you're handling the SizeChanged event, or if you're doing any other overrides on the layout of your control.

Fp answered 12/3, 2009 at 1:23 Comment(2)
This is the problem I'm seeing. The linked blog post suggests only doing your layout stuff on initial load and when the silverlight app (the containing user control) changes its size. This might work for me, but I've not yet tested it when doing animations and other actions. Thanks for the help!Aerostat
Wayback machine to the rescue: web.archive.org/web/20110203182929/http://jeffhandley.com/…Fp
H
6

A common cause is handling SizeChanged and then in the handler doing something that affects the size of the element. Sometimes this is not obvious - it could be modifying child elements which affect the size of their container for instance.

Hedberg answered 12/3, 2009 at 1:30 Comment(0)
R
4

1.If you are using LongListSelector inside ScrollViewer, better remove that. I was facing the same problem and my LongListSelector was inside ScrollViewer. During ItemRealized event, was getting this error.

2.Don't use updatelayout() inside itemrealized..I was using something like

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

Simply use ScrollTo

3.If you are using image inside longlistselector, make sure to set the height and width of the image.

Refutation answered 6/3, 2014 at 9:36 Comment(0)
C
1

I had the same problem and what i did was put all the layout updates (size changes) in a "invoke" delegate en invoked later, it stops crashing but you there is a good change it's stuck in a loop

Crosley answered 17/5, 2011 at 12:18 Comment(0)
I
0

I had the same problem but it only occurred extremely rarely, my code hasn't changed for years and only recently someone managed to experience it.

I had a TextBlock inside a LongListSelector DataSource and its FontSize was set to 21. Changing the FontSize to ANY other value fixed the problem for me...

My LongListSelectors is inside a 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>

Fix:

<TextBlock Text="{Binding getTotalPlaytimeFormatted}" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="22" >
Impeach answered 12/5, 2015 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.