Ошибка Silverlight "Макет с установленным циклом макета не может быть завершен" при использовании настраиваемого элемента управления
Я создаю настраиваемый элемент управления в Silverlight, получая из ContentControl и делая специальное форматирование, чтобы поместить заслонку за содержимое.
Я почти получил его работу, но недавно столкнулся с причудливой ошибкой. Он отлично работает, если содержит ничего, кроме границы, или Grid/Stackpanel/etc, который не имеет явно определенной высоты и ширины.
Я получаю ошибку JavaScript в IE, и в тексте говорится:
Ошибка выполнения 4008... Обнаруженный цикл компоновки... Макет не может быть завершен.
Если я укажу высоту и ширину на содержащейся grid/stackpanel/etc, она отлично работает.
Существует тонна в Интернете об этой ошибке, когда используется слишком много текстовых полей (более 250), но я могу воспроизвести свою ошибку с помощью одной кнопки в сетке.
У меня нет текстовых полей на странице. Ошибка связана с обнаруженным бесконечным циклом. Я установил несколько контрольных точек в коде, и кажется, что событие "SizeChanged" получает много во время рендеринга, и каждый раз, когда высота/ширина увеличивается на 10.
Я предполагаю, что установка высоты/ширины по умолчанию заставляет его пропускать это увеличение числа, но я не знаю, почему эта ошибка происходит.
Кто-нибудь сталкивался с этим или имел какие-то идеи?
Ответы
Ответ 1
Существует хорошая запись в блоге об этой ошибке здесь.
Баснически, что может произойти, вы меняете какой-то размер в MeasureOverride
где-то, что вызывает другую меру, которая меняет размер, что вызывает меру и так далее. Я столкнулся с этим раньше и исправил его, удалив любой код, вызвавший обновление макета, или вызвал обновление макета во время цикла компоновки.
Обновление: так как сообщение в блоге пропало, цитируя его здесь полностью:
Продолжая серию gotchas для Silverlight 2, я хотел поговорить об общей ошибке, которую люди видят. Эта ошибка является чем-то новым, что вы можете увидеть при перемещении кода из бета-версии 2 в Release Candidate или позже. В бета-версии 2, если механизм компоновки обнаружил цикл, он не выдавал никаких ошибок; как я понимаю, макет был просто прерван. Но с битами post Beta2 выдается ошибка.
Ошибка, которую вы получите, будет указывать в качестве сообщения "Обнаруженный цикл". Это сообщение об ошибке очень точное - механизм компоновки обнаружил цикл в вашем макете; или другой способ сказать это, у вас есть бесконечный цикл в вашем макете.
Самым большим виновником этой ошибки является код внутри обработчика событий LayoutUpdated. Если ваш обработчик обработчика LayoutUpdated делает что-либо, чтобы изменить макет вашего элемента управления, это приведет к тому, что событие LayoutUpdated будет возобновлено снова и снова и снова...: -)
Иногда вам нужно иметь код изменения макета в этом обработчике событий, так что что делать?
Во-первых, вы должны подумать, действительно ли вам нужны изменения компоновки при каждом вызове LayoutUpdated. Было бы достаточно обработать событие Loaded, а также событие Application.Current.Host.Content.Resized. Между этими двумя событиями вы получите уведомление, когда элемент управления загрузится в визуальное дерево, и вы получите уведомление в любое время, когда размер хоста будет изменен, что может привести к необходимости повторного изменения макета. Сценарии, такие как модальные диалоги, должны относиться к этой категории.
Во-вторых, если вам действительно нужно использовать LayoutUpdated, вам просто нужно будет поместить некоторые условия вокруг изменений вашего макета. Например, если вы вычисляете новую ширину и высоту для своего элемента управления, прежде чем устанавливать ширину и высоту, убедитесь, что текущие значения отличаются от того, что вы рассчитали. Это позволит первому событию LayoutUpdated изменить размер вашего элемента управления, который запускает другое событие LayoutUpdated, но это событие распознает, что нет работы, и цикл закончится.
Эти же правила будут применяться, когда вы обрабатываете событие SizeChanged или выполняете какие-либо другие переопределения в макете вашего элемента управления.
Ответ 2
Общей причиной является обработка SizeChanged
, а затем обработчик делает что-то, что влияет на размер элемента. Иногда это не очевидно - это может быть изменение дочерних элементов, которые, например, влияют на размер их контейнера.
Ответ 3
1.Если вы используете LongListSelector внутри ScrollViewer, лучше удалите это. Я столкнулся с той же проблемой, и мой LongListSelector находился внутри ScrollViewer. Во время события ItemRealized была получена эта ошибка.
2. Не используйте updatelayout() внутри itemrealized.. Я использовал что-то вроде
list.UpdateLayout();
list.ScrollTo(e.Container.Content);
Просто используйте ScrollTo
3.Если вы используете изображение внутри longlistselector, не забудьте установить высоту и ширину изображения.
Ответ 4
У меня была такая же проблема, и я сделал, чтобы все обновления макета (изменения размера) в "invoke" делегировании en были вызваны позже, он перестает сбой, но у вас есть хорошее изменение, которое оно застряло в цикле
Ответ 5
У меня была такая же проблема, но это происходило крайне редко, мой код не менялся годами, и только недавно кому-то удалось это испытать.
У меня был TextBlock внутри LongListSelector DataSource, а его FontSize был установлен на 21. Изменение FontSize на любое другое значение устранило проблему для меня...
My 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>
Fix:
<TextBlock Text="{Binding getTotalPlaytimeFormatted}" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="22" >