Sunday, February 16, 2014

How to avoid the Exception "A cycle occurred while laying out the GUI." in a Windows store APP


The Observed Problem

Sometimes the exception "A cycle occurred while laying out the GUI." occurs in Windows 8 store application in an unpredicatble way. This can be very frustrating especially when the problem is observed only on some computers and not on others .

Note that when this occurs on a released and deployed Application the Application terminates silently without indicating any error message.

The explanation

The reason for this exception is in fact very simple: as the description says, we have an endless loop in the layout of the GUI. I have found that this nearly always occurs in the SizeChanged event handler.

  
 border.SizeChanged += _SizeChanged;  
 

What can be puzzling is that this can occur even if the SizeChanged Handler does something that should not trigger any endless loop. Example

  
 private  void _SizeChanged(object sender,
                     Windows.UI.Xaml.SizeChangedEventArgs e)
        {
            if (e.NewSize.Width < 150)
            {
                (border.Child as TextBlock).FontSize = 40;   
            }
            else
            {
                (border.Child as TextBlock).FontSize = 80;   
            }
        }
    }
 

Theoretically, the above code should never trigger an endless loop. But this is not the case. For some graphic résolutions, this method triggers endless calls to the _SizeChanged event Handler.

The work around

There is a simple way to make sure that the SizeChanged event is not called endlessly: ignore the event when it is called for nothing. Detecting useless SizeChanged events can easily be done by comparing the old size and the new size; if they are identical then the SizeChanged event was called for nothing and it can safely be ignored.

 
 if (e.PreviousSize != e.NewSize)   
 

Example: to prevent any risk of endless loop we should update the the following code to make it look like this:

  
 private  void _SizeChanged(object sender, 
                     Windows.UI.Xaml.SizeChangedEventArgs e)
        {
            if (e.PreviousSize != e.NewSize)
            {
                if (e.NewSize.Width < 150)
                {
                    (border.Child as TextBlock).FontSize = 40;   
                }
                else
                {
                    (border.Child as TextBlock).FontSize = 80;   
                }
            }
        }