Windowstemplatestudio: Adaptive Triggers do not work in Windows Phone Emulator

Created on 11 Jun 2017  路  17Comments  路  Source: microsoft/WindowsTemplateStudio

Due to DisplayMode by default is set to CompactInLine the adaptive triggers do not fire if the app is launched on a phone emulator. The proper DisplayMode for a phone should be set to Overlay.

Can Close Out Soon Microsoft on point bug

All 17 comments

I've noticed the same issue (on a real device). I think the OnStateChanged()-Event should be somehow fired on inital launch.

Is this in dev nightly or production?

I'm facing this in production

Quick workaround
If using Code Behind

In ShellPage.xaml.cs
Change the Initialize method to be like this:

    private void Initialize()
    {
        NavigationService.Frame = shellFrame;
        NavigationService.Frame.Navigated += NavigationService_Navigated;
        PopulateNavItems();

        if (Window.Current.Bounds.Width < 640)
        {
            GoToState(NarrowStateName);
        }
    }

Add the method GoToState

    private void GoToState(string stateName)
    {
        switch (stateName)
        {
            case PanoramicStateName:
                DisplayMode = SplitViewDisplayMode.CompactInline;
                break;
            case WideStateName:
                DisplayMode = SplitViewDisplayMode.CompactInline;
                IsPaneOpen = false;
                break;
            case NarrowStateName:
                DisplayMode = SplitViewDisplayMode.Overlay;
                IsPaneOpen = false;
                break;
            default:
                break;
        }
    }

Change WindowStates_CurrentStateChanged to be

    private void WindowStates_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
    {
        GoToState(e.NewState.Name);
    }

If using MVVMBasic or MVVM Light

In ShellViewModel.
Add GoToState as above.

Change the following methods to be as below.

    public void Initialize(Frame frame)
    {
        NavigationService.Frame = frame;
        NavigationService.Frame.Navigated += NavigationService_Navigated;
        PopulateNavItems();

        if (Window.Current.Bounds.Width < 640)
        {
            GoToState(NarrowStateName);
        }
    }

    private void OnStateChanged(VisualStateChangedEventArgs args)
    {
        GoToState(args.NewState.Name);
    }

Hopefully, the above workaround unblocks anyone affected by this.
Now to discuss the best solution.

There are two issues here.

  1. What's the best way to address this?
  2. How did we get here? and does it highlight any other potential issues or a need to improve any processes?

Issue 1
In the past, I've always ended up with a bit of code behind to query the screen bounds for this kind of thing. I don't think there's a pure XAML way to address this.
However, I do think we could move a some of the current CS code into XAML using VisualState Setters.
We could also do with a review and guidance on which pages (beyond NavPanel) should include their own adaptive triggers for with changes. At the moment it's not all and it would be good to remove the inconsistencies or document why they're there.

Open to input from anyone with input and expertise in this area and how they may have addressed this issue in the past.

Issue 2

  • If sizes to use for the breakpoints came from the design team can they (or anyone else) provide any "official" guidance on how to handle this situation?
  • We didn't pick this up earlier as we're not doing any detailed routine testing on Mobile. Does this need to change? Should we test for more than just the desktop? and if so, what?
  • Do we need to be more thorough in (re)testing everything? [TBH I've not looked at most of the code that's generated in as critical an eye as I would for something I was paid for. Maybe I need to have a look at things a bit closer, but also want to acknowledge I can't do everything.]
  • As we grow, can we just rely on more sets of eyes picking up things like this earlier?

Would be good to get input from some more people before submitting a PR with the workaround.

@mrlacey your fix is working for me (MVVM Light), thanks!

馃槥 My hacky workaround was not an elegant way of solving this issue and it's disappointing to see that's what's been implemented. There was a reason I didn't implement this as a fix when looking at the original bug.

Would be good to get input from some more people before submitting a PR with the workaround.

I have the following issues with the solution as implemented:

  • It ignores the issues I call out above.
  • It ignores the questions I've asked above.
  • It ignores the other, related, possible improvements also called out above.
  • It only solves the issue for the narrow state. It doesn't set the correct state if it should be panoramic.
  • It doesn't solve the issue for MasterDetail pages which potentially have the same issue in a blank app.
  • It relies on the hard-coded breakpoint value being changed in both the XAML and code-behind if ever changed. which is not ideal.

@mrlacey you have 100% valid questions. We implement this way as a "quick and dirty" workarround, but maybe we should consider review it and give a deep reflection.

Thanks for pointing.

I think we're ok with quick and dirt inside the engine, for templates, the bar is much higher.

This code is in the templates.

If doing something a quick fix an issue needs to be raised at the same time to go back and address the issue in more detail at a later time otherwise it will be forgotten and not get done.

There are a few possibilities.

Setting changes from XAML is more clean but it is less flexible.

``` xaml

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="WindowStates">
            <i:Interaction.Behaviors>
                <ic:EventTriggerBehavior EventName="CurrentStateChanged">
                    <ic:InvokeCommandAction Command="{x:Bind ViewModel.StateChangedCommand}"/>
                </ic:EventTriggerBehavior>
            </i:Interaction.Behaviors>
            <VisualState x:Name="PanoramicState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="1024"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="NavigationMenu.DisplayMode" Value="CompactInline"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="WideState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="640"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="NavigationMenu.DisplayMode" Value="CompactInline"/>
                    <Setter Target="NavigationMenu.IsPaneOpen" Value="False"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="NarrowState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="NavigationMenu.DisplayMode" Value="Overlay"/>
                    <Setter Target="NavigationMenu.IsPaneOpen" Value="False"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

We have also a difficult way to close the menu on item clicked, making some things in Xaml and others in view model CS.

I propose to improve the workaround:

```CSharp

        private const string PanoramicStateName = "PanoramicState";
        private const string WideStateName = "WideState";
        private const string NarrowStateName = "NarrowState";
        private const double WideStateMinWindowWidth = 640;
        private const double PanoramicStateMinWindowWidth = 1024;

        public void Initialize(Frame frame)
        {
            NavigationService.Frame = frame;
            NavigationService.Frame.Navigated += NavigationService_Navigated;
            PopulateNavItems();

            InitializeState(Window.Current.Bounds.Width);
        }

        private void InitializeState(double windowWith)
        {
            if (windowWith < WideStateMinWindowWidth)
            {
                GoToState(NarrowStateName);
            }
            else if (windowWith < PanoramicStateMinWindowWidth)
            {
                GoToState(WideStateName);
            }
            else
            {
                GoToState(PanoramicStateName);
            }
        }

        private void GoToState(string stateName)
        {
            switch (stateName)
            {
                case PanoramicStateName:
                    DisplayMode = SplitViewDisplayMode.CompactInline;
                    break;
                case WideStateName:
                    DisplayMode = SplitViewDisplayMode.CompactInline;
                    IsPaneOpen = false;
                    break;
                case NarrowStateName:
                    DisplayMode = SplitViewDisplayMode.Overlay;
                    IsPaneOpen = false;
                    break;
                default:
                    break;
            }
        }

What do you think @mrlacey ?

Added in PR

Also add chart page to title trigger composition template (new bug found testing on Lumia Phone)

Has this been resolved yet? Shouldn't most of this code live inside the actual navpane control itself?

There's a workaround in but it's not perfect. The underlying issue is there's nothing in the SDK that will trigger the event to set the appropriate state on launch purely from XAML. While we could change it so that the default state was the small/narrow/phone one this still wouldn't be a 100% solution and we'd still have to resort to something from code behind.
I think we can close this out as the real issue is a limitation of the SplitView control.

I think we can close out this.

let me ask around if there isn't something magical we are missing. if not we can close this out

Was this page helpful?
0 / 5 - 0 ratings