Windows 8.1 SemanticZoom object crashes app with a Win32 exception when setting the Visibility to Collapsed

Written by Tom Verhoeff. Posted in Windows 8

While working on retargeting one of our existing Windows 8 apps to Windows 8.1 I ran into an issue with the SemanticZoom object. Because of the new Windows Sizes and scaling options in Windows 8.1 it’s recommend to handle the Page’s SizeChanged event to switch to your various ViewStates. Please see this MSDN page for instructions on how to implement this.

This is the piece of code that handles VisualStateTransitions:

void GroupedItemsPage_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
        if (e.NewSize.Width < 500) 
            { 
                VisualStateManager.GoToState(this, "MinimalLayout", true); 
            } 
            else if (e.NewSize.Width < e.NewSize.Height) 
            { 
                VisualStateManager.GoToState(this, "PortraitLayout", true); 
            } 
            else 
            { 
                VisualStateManager.GoToState(this, "DefaultLayout", true); 
            } 
        } 

Unfortunately there appears to a bug in the SemanticZoom object that causes a Win32-exception and crash when one of those state transitions involves Collapsing a SemanticZoom object. This only happens when executing the transition within the SizeChanged event-handler.

After messing around with this issue for a bit I figured out a simple workaround. Scheduling the VisualState transition through the UI-thread’s dispatcher performs the transition without raising any exceptions. If your “MinimalLayout” state contains said transition this code would work:

async void GroupedItemsPage_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
        if (e.NewSize.Width < 500) 
            { 
                var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
                await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => VisualStateManager.GoToState(this, "MinimalLayout", true));

            } 
            else if (e.NewSize.Width < e.NewSize.Height) 
            { 
                VisualStateManager.GoToState(this, "PortraitLayout", true); 
            } 
            else
            { 
                VisualStateManager.GoToState(this, "DefaultLayout", true); 
            } 
        }