Microsoft-ui-xaml: Show NavigationPane on collapsed by default on PaneDisplayMode Left

Created on 6 May 2020  ยท  36Comments  ยท  Source: microsoft/microsoft-ui-xaml

Describe the bug
Unable to show NavigationPane collapsed by default for PaneDisplayMode Left

Steps to reproduce the bug

  1. Create a new UWP App
  2. Add a NavigationView Control to the MainPage
  3. Set PaneDisplayMode to Left and IsPaneOpen to false

I've attached a repro project : App207.zip

Actual behavior
The NavView pane is shown expanded on on application start

Expected behavior
The NavView pane should be collapsed on application start

Version Info

NuGet package version: Microsoft.UI.Xaml 2.4.0


| Windows 10 version | Saw the problem? |
| :--------------------------------- | :-------------------- |
| Insider Build (xxxxx) | |
| November 2019 Update (18363) | yes |
| May 2019 Update (18362) | |
| October 2018 Update (17763) | |
| April 2018 Update (17134) | |
| Fall Creators Update (16299) | |
| Creators Update (15063) | |


| Device form factor | Saw the problem? |
| :-------------------- | :------------------- |
| Desktop | yes|
| Mobile | |
| Xbox | |
| Surface Hub | |
| IoT | |

Additional context
Originally reported on Windows Template Studio https://github.com/microsoft/WindowsTemplateStudio/issues/3644

area-NavigationView help wanted needs-cherrypicktorelease team-Controls

Most helpful comment

I would like to look into this.

All 36 comments

I would like to look into this.

@anawishnoff @ojhad I assume this is not by design ?

I was able to work around it by adding to the the WTS' ShellViewModel's OnLoaded method.

        private async void OnLoaded()
        {
            _navigationView.IsPaneOpen = false;

The combinations

  • PaneDisplayMode::LeftCompact & IsPaneOpen = true
  • PaneDisplayMode::LeftMinimal & IsPaneOpen = true

are also not working (pane is closed in both cases).

Here the question as well: Is this by design or should this be fixed?

I believe this is a bug. The behavior should follow those properties. @anawishnoff @ojhad as FYI. Please comment if you disagree.

@ranjeshj It seems like a bug to me, the IsPaneOpen property is there for a reason and should react when it's changed.

I made the following observation while working on this issue:
NavigationView.IsPaneOpen is - by default - true. Which means that if we set the PaneDisplayMode to LeftMinimal/LeftCompact without setting the IsPaneOpen property as well, the NavigationView pane should be open by default. A problem arises because programmatically setting the selected item in these pane display modes still causes the pane to be closed. This problem manifests itself in the following, probably not so uncommon scenario: A default selected navview item is set in the NavView's Page's Loaded event, like this.NavView.SelectedItem = SomeNavViewItem. What this means is that even though we left IsPaneOpen=true, upon opening the app page, the NavigationView's pane is closed.

To solve this, we could keep the pane open in LeftMinimal/LeftCompact mode when a selected item is set programmatically. As no user interation with the app happened, it sounds reasonable to me to keep the pane open in this case. This will not change any other pane closing behavior (for example initiated by a user action such as clicking, etc...).

Thoughts?

There's also the Auto PaneDisplayMode we need to clarify. How will this mode play together with the IsPaneOpen property? Would IsPaneOpen only affect the initial pane state and resizing the app window would automatically open or close the pane if required (as it does today)?

Also observe that currently, if I use the Auto PaneDisplayMode and I close the pane via this.NavView.IsPaneOpen=false when we are in the left expanded pane configuration, the pane is not opened automatically again on subsequent window resizes. Please see the following gif which illustrates this:
navview-panedisplaymode-auto-pane-behavior

It would be best if we can pick a consistent behavior here for the Auto PaneDisplayMode working together with the IsPaneOpen property. I do think setting the IsPaneOpen property in XAML should at most affect the initial pane state in the Auto PaneDisplayMode. Does that then mean we should change the behavior demonstrated in the gif above? For example, while setting IsPaneOpen to false would still close the pane as in the gif, future resizing of the app will open the pane automatically again.

Here my 2cents:

If you set PaneDisplayMode, this will override whatever IsOpen is set to. So LeftCompact would have IsPaneOpen=false unless changed by developers. I think Auto mode should update the IsPaneOpen flag accordingly.

Since there are a lot of different configurations to think about, here's a table of what I think would be the best behavior:

| PaneDisplayMode | IsPaneOpen value | Pane should be open |
| -------------------- | ----------------------- | ------------------------ |
| Auto | No | โ“ (Depending on width) |
| Left | No | โŒ |
| LeftCompact | No | โŒ |
| LeftMinimal | No | โŒ|
| Top | No | โŒ |
| Auto | Yes | โœ” (Will change depending on resizing though) |
| Left | Yes| โœ”|
| LeftCompact | Yes | โœ”|
| LeftMinimal | Yes | โœ”|
| Top | Yes | โŒ |

@Chingucoding I'm not sure I like the idea that the interaction behavior of PaneDisplayMode Auto and IsPaneOpen is not consistent in the table. I believe we really should pick one behavior for Auto mode and then use it no matter the initially accompanying IsPaneOpen value.

Approach 1

IsPaneOpen affects the initial state of the pane in Auto mode. The pane is then opened/closed upon window resizing just like today. So the following XAML

<NavigationView PaneDisplayMode="Auto"
                IsPaneOpen="False" />

guarantees the pane to be closed initially no matter the window size and

<NavigationView PaneDisplayMode="Auto"
                IsPaneOpen="True" />

guarantees the pane to be opened initially on any window size.

Approach 2

Keep the current behavior of the NavigationView in Auto mode. The initial value of IsPaneOpen is ignored and the pane is opened/closed automatically depending on the window size. So the following two XAML snippets have the same result:

<NavigationView PaneDisplayMode="Auto"
                IsPaneOpen="False" />
<NavigationView PaneDisplayMode="Auto"
                IsPaneOpen="True" />

The pane would initially be opened when the window is wide enough, or closed otherwise.

I'm currently slightly in favor of keeping the current behavior as that will give developers the full adaptive behavior of the Auto PaneDisplayMode as described in the docs today.

For both approaches

Setting IsPaneOpen after the initial setup phase (for example as soon as NavigationView.Loaded is called?) will affect the pane, however, since we are in Auto mode, resizing the window will still open/close the pane automatically if required.

TL;DR
I'm currently inclined to only respect the IsPaneOpen property during initial setup fo the NavigationView when we are not in the the PaneDisplayMode Auto (and Top mode too). This will keep the current behavior for Auto and match the documentation as well as the adaptive feature of the Auto pane display mode.

guarantees the pane to be closed initially no matter the window size and

The problem is that afaik IsPaneOpen has a default value, so you won't be able to have either the "open as needed on start" or the "pane should be closed regardless of size" states.

I think it would be better to not ignore IsPaneOpen=true in Auto mode. If you don't set it, you still get the same behavior as outlined in the docs. If you set it to true, it only opens on start, after that you still get the auto behavior.

I'm currently slightly in favor of keeping the current behavior as that will give developers the full adaptive behavior of the Auto PaneDisplayMode as described in the docs today.

Allowing to change the startup behavior does not change that. If you don't set the value, the behavior does not change. It would still be all automatic and according to documentation.

I'm currently inclined to only respect the IsPaneOpen property during initial setup fo the NavigationView when we are not in the the PaneDisplayMode Auto (and Top mode too). This will keep the current behavior for Auto and match the documentation as well as the adaptive feature of the Auto pane display mode.

The problem is the following scenario: You want to use auto mode, but also want the NavigationView pane to be open at start, e.g. to show all of the available items. With approach 2 there wouldn't be a way to do this except switching the displaymode at some point.

The problem is the following scenario: You want to use auto mode, but also want the NavigationView pane to be open at start, e.g. to show all of the available items. With approach 2 there wouldn't be a way to do this except switching the displaymode at some point.

You can set IsPaneOpen to true in the NavigationView.Loaded event for example if you need to modify the behavior of the Auto display mode.

I think it would be better to not ignore IsPaneOpen=true in Auto mode. If you don't set it, you still get the same behavior as outlined in the docs. If you set it to true, it only opens on start, after that you still get the auto behavior.

The current default value of IsPaneOpen is True so the XAML snippets

<NavigationView PaneDisplayMode="Auto"/>

and

<NavigationView PaneDisplayMode="Auto"
                IsPaneOpen="True" />

should give the same result.

We can modify the behavior and the documentation, but based on the current state of the documentation, it is my understanding that Auto mode initially ignoring the IsPaneOpen setting is intended and not a bug.

The current default value of IsPaneOpen is True so the XAML snippets

I did not know that. In that case, I agree, we should leave that part as is.

You can set IsPaneOpen to true in the NavigationView.Loaded event for example if you need to modify the behavior of the Auto display mode.

That's kind of a weak argument, the main issue of this thread would also probably be fixed by setting the value in on loaded. However that is more of a workaround in my opinion.

But given the current situation, we probably shouldn't touch the Auto for now.

That's kind of a weak argument, the main issue of this thread would also probably be fixed by setting the value in on loaded. However that is more of a workaround in my opinion.

It wasn't meant as an argument but just to show that you can rather easily modify the IsPaneOpen state even in Auto mode before the pane is actually shown if so required. As I said, my main argument to not touch the behavior in Auto mode is the behavior of it currently outlined in the docs. If that description is incorrect (in not mentioning that IsPaneOpen can be used to set the initial pane state in Auto mode) then we need to correct that behavior.

It wasn't meant as an argument but just to show that you can rather easily modify the IsPaneOpen state even in Auto mode before the pane is actually shown if so required. As I said, my main argument to not touch the behavior in Auto mode is the behavior of it currently outlined in the docs. If that description is incorrect (in not mentioning that IsPaneOpen can be used to set the initial pane state in Auto mode) then we need to correct that behavior.

I don't think that the current auto behavior is out of sync with the documentation. I thought we might be able to improve it but since IsPaneOpen=true there isn't much to do here I think.

So to recap:

| PaneDisplayMode | IsPaneOpen value | Pane should be open |
|-------------|-------------|-----|
| Auto | True | โ“ (depending on app width)
| LeftMinimal | True | โœ”|
| LeftCompact | True | โœ”|
| Left | True | โœ”|
| Top | True | (no pane to open) |
| Auto | False| โ“ (depending on app width)
| LeftMinimal | False| โŒ|
| LeftCompact | False| โŒ|
| Left | False| โŒ|
| Top | False| (no pane to open) |

The table above shows the effect of combining the IsPaneOpen and PaneDisplayMode APIs in XAML Markup, like this:

<NavigationView IsPaneOpen="False"
                PaneDisplayMode="Left" />

This leaves my question about the behavior when the PaneDisplayMode is set to Auto and we set the IsPaneOpen property after the NavigationView has been loaded. See the gif below for the current behavior:
navview-panedisplaymode-auto-pane-behavior
Observe that if I close the pane via this.NavView.IsPaneOpen=false while we are in the left expanded pane configuration, the pane is not opened automatically again on subsequent window resizes. Since we are in Auto display mode though, I believe we should preserve the adaptive pane behavior here which means after manually closing (or opening) the pane via IsPaneOpen (as seen above in the gif), future window resizing will open/close the pane again automatically. In other words, in the above gif the pane would be opened again automatically once the window width is large enough to trigger the adaptive pane opening behavior of the Auto mode.

@chingucoding @anawishnoff Your thoughts?

The table looks fine to me.

Regarding the IsPaneOpen in Automatic mode, I would say that this is actually a bug. It somewhat "breaks" the automatic aspect of "Auto". In the DisplayMode "Auto", I would expect the IsPaneOpen property to act like an "instant" toggle, that is, if you set the value, it opens/closes the pane right now, anything that happens after that is something that switch of IsPaneOpen just done by the developer is not impacted by that. If you set IsPaneOpen to true, the pane will open, but if the window gets more narrow, it will close again.

@anawishnoff to chime in on the expected behavior for this API.

@anawishnoff What are your thoughts on the PaneDisplayMode and IsPaneOpen API behavior outlined here?

Sorry for the late reply on this!

The table makes sense to me, and your example of manually setting IsPaneOpen = true in auto mode is interesting. The whole point of Auto mode is that the NavigationView resizes depending on the current situation. I think that being able to set IsPaneOpen as a specific one-off instruction and then having it go back to doing its Auto thing makes sense to me.

@YuliKl Feel free to chime in if you disagree.

I also think all this makes sense.

One scenario I want to highlight is about the LeftCompact and LeftMinimal modes (and also when Auto places NavigationView into those modes): Because the Pane is open as a light-dismiss overlay in these modes, I'd like to avoid having the pane show as open on app launch. Respecting the app developer setting and launching with the pane open when IsPaneOpen gets explicitly set to True is fine. Just want to make sure that we're not defaulting to an open pane in these modes without app developer intervention.

If I'm following the discussion correctly I believe this will not be an issue. Just wanted to make sure to spell out the intended default behavior.

One scenario I want to highlight is about the LeftCompact and LeftMinimal modes (and also when Auto places NavigationView into those modes): Because the Pane is open as a light-dismiss overlay in these modes, I'd like to avoid having the pane show as open on app launch. Respecting the app developer setting and launching with the pane open when IsPaneOpen gets explicitly set to True is fine. Just want to make sure that we're not defaulting to an open pane in these modes without app developer intervention.

@YuliKl I think this describes a different behavior than the one outlined above (and actually quite matches the current pane launch behavior more).

With the proposed table shown here, a XAML markup like

<NavigationView PaneDisplayMode="LeftMinimal"
                IsPaneOpen="True" />

would launch the pane in an opened state and a XAML markup like

<NavigationView PaneDisplayMode="LeftMinimal"
                IsPaneOpen="False" />

would launch the pane in a closed state.

The problem here is that NavigationView.IsPaneOpen defaults to true. In other words, this XAML markup below would also launch the pane in an opened state:

<NavigationView PaneDisplayMode="LeftMinimal"/>

This does not match the behavior you've outlined above where a developer has to explicitly set IsPaneOpen to true in order for the pane to be opened on launch when in LeftMinimal or LeftCompact mode.

Instead, with the currently existing pane launch behavior in UWP/WinUI, if the developer wants the pane to be opened in the LeftMinimal/LeftCompact states on launch, they could use the NavigationView.Loaded event and explicitly set NavigationView.IsPaneOpen to true which would then open the pane.

This sounds more like what you've described above as desired behavior.

So, if I revise the table with your desired behavior, this will be the new behavior of instantiating a NavigationView control like this:

<NavigationView PaneDisplayMode="[SomeMode]"
                IsPaneOpen="[SomeBool]" />

| PaneDisplayMode | IsPaneOpen value | Pane will be opened | Remarks |
|-------------|-------------|-----|---|
| Auto | True | โ“ | If NavigationView is set into LeftMinimal/LeftCompact mode the pane will be launched in a closed state and IsPaneOpen will be set to false. If the NavigationView is set into Left mode the pane will be launched in an opened state |
| LeftMinimal | True | โŒ| IsPaneOpen will be set to false |
| LeftCompact | True | โŒ | IsPaneOpen will be set to false |
| Left | True | โœ”| - |
| Top | True | - | No pane to open |
| Auto | False| โŒ | Pane will be launched in a closed state for every app window width |
| LeftMinimal | False| โŒ| - |
| LeftCompact | False| โŒ| - |
| Left | False| โŒ| - |
| Top | False| - | No pane to open |

This would essentially be the behavior we are seeing today, except that in WinUI right now the Left pane display mode will default to launch the pane in an opened state, even if IsPaneOpen is set to false:

<!-- This will launch the pane in an opened state today. -->
<NavigationView PaneDisplayMode="Left"
                IsPaneOpen="False" />

This is also the case if the Auto mode puts the NavigationView in Left mode.

Not affected by this revision will be the suggestion of IsPaneOpen acting as a one-off instruction in Auto mode if set after the NavigationView pane has been launched in its initial state.

@YuliKl @anawishnoff Does this sound reasonable?

Thank you, @Felix-Dev, sounds good.

@YuliKl @anawishnoff

We might have to look at IsPaneOpen acting as a one-off instruction in Auto mode again. Outside of explicitly setting IsPaneOpen to false, the pane can also be closed by using the pane toggle button:

navview-panetoggle

As you can see, after we close the pane via the toggle button, it is o longer automatically being reopened even though we are in Auto mode. Instead, we treat this as a "forced close", so the user has to explicitly open the pane again.

I think we should treat closing the pane via the Toggle button and explicitly setting IsPaneOpen to false the same way. In other words, I would either keep the current behavior of setting IsPaneOpen to false in Auto mode (which is the pane won't automatically be re-opened) or adjust the behavior of the pane toggle button when in Auto mode (so that the pane will automatically be re-opened when app window is wide enough).

As we are treating closing the pane via the toggle button as a forced close deliberately, I think we should keep the current behavior of setting IsPaneOpen while the NavigationView is already loaded. So no one-off instruction then.

What do you think?

@YuliKl @anawishnoff Friendly ping in cased it got missed (feel free to ignore if you are currently busy with something else).

I think we should treat closing the pane via the Toggle button and explicitly setting IsPaneOpen to false the same way.

Yes! One command is coming from the end-user, the other from the app developer, but they are both intended to have the same result on NavigationView's appearance/state.

And thank you for the ping @Felix-Dev, the quick reminder is really helpful in trying to keep up with active discussions.

  1. A user trying to open the left-pane-menu by stretching the client - making it wider is poor UX design.
  2. A user trying to making the client area wider, to give them more working area, but then having the left-pane-menu slide out and take up the client area they are trying to gain is poor UX design.
  3. It's much cleaner to use the button to open the left-pane-menu. Give the user precise control, don't interfere with their interaction. Good UX design.
  4. Don't ignore the state/setting of a property. If you want to 'ignore it' set the state/setting of the property to the value you want, a value that 'always' represents the current behavior.
    i. A properties value that doesn't represent the behavior it wrong. This is poor engineering.

I have one concern, I'm designing apps for Xbox, so we use focus to open the NavigationView.
Suppose I set the NavigationView.PaneDisplayMode=LeftCompact, and a Button.
ๆ— ๆ ‡----้ข˜

I have to use focus to open the NavigationView. But when press the left button, NavigationView closes immediately when opened.

private void btn_PreviewKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
        {
            switch (e.OriginalKey)
            {
                case VirtualKey.Left:
                case VirtualKey.GamepadDPadLeft:
                case VirtualKey.GamepadLeftThumbstickLeft:
                    ShellPage.shellPage.navigationView.IsPaneOpen = true;
                    e.Handled = true;
                    break;
            }
        }

@hupo376787 Could you explain more? Is navigation view is already open (since you are saying that it is closing). Can you share a video or gif ? Thanks!

@hupo376787, the View button on the Xbox controller (the small round button with two overlapping rectangles as its icon) opens NavigationView. Does that help with your scenarios?

@hupo376787 Could you explain more? Is navigation view is already open (since you are saying that it is closing). Can you share a video or gif ? Thanks!

Navigation is LeftCompact. When putting focus on the button and press left, this happens. The same happens on Xbox.

GIF

@hupo376787, the View button on the Xbox controller (the small round button with two overlapping rectangles as its icon) opens NavigationView. Does that help with your scenarios?

Nope, view button still can not open NavigationView.

See ๐Ÿ‘‡
cc6bd06f459afd0e4c60617496d18355 (2)

@hupo376787 what is you remove the custom code you've added? The View button is default behavior what's working for me in Xaml Controls Gallery.

@YuliKl I set IsPaneToggleButtonVisible="False".

See my sample repo.

@hupo376787 This appears to be fixed starting with WinUI 2.5.0-prerelease.200812001. Can you report the fix on your systems as well when using this preview version (or a newer one)?

@Felix-Dev Thx, mine is 2.4.3. I update to 2.5.0-preview, seems ok on my pc now.

Was this page helpful?
0 / 5 - 0 ratings