Microsoft-ui-xaml: NavigationView hierarchy dropdowns don't have rounded corners

Created on 7 May 2020  路  22Comments  路  Source: microsoft/microsoft-ui-xaml

Describe the bug
When NavigationView has hierarchical items and you're in Left compact view mode or Top view mode, and you click on an item which causes a dropdown/flyout to appear, that dropdown/flyout doesn't have rounded corners. (See screenshot)

Steps to reproduce the bug

  1. Open Controls gallery (or any app that implements WinUI 2.4 NavView)
  2. Shrink the window so NavigationView goes into compact mode (or switch to Top mode)
  3. Click on any item that has some items in hierarchy beneath it
  4. Look at the dropdown/flyout corners

Expected behavior
Corners of the dropdown/flyout should be rounded, just as similar controls (Flyout, MenuFlyout, ...)

Screenshots
issue

Version Info
XAML Controls Gallery 1.2.15.0, WinUI 2.4.0

NuGet package version:
Microsoft.UI.Xaml 2.4.0

| Windows 10 version | Saw the problem? |
| :--------------------------------- | :-------------------- |
| Insider Build (19619) | Yes |
| November 2019 Update (18363) | |
| 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

area-NavigationView help wanted needs-cherrypicktorelease team-Controls

All 22 comments

@anawishnoff @chigy should we make the corners rounded ?

@chigy would be the authority on this, but if there's rounded corners in Flyout and MenuFlyout I don't see why there wouldn't be here.

If no one else is working/wants to work on this and this is confirmed to be an oversight, I would like to fix this.

As it is a flyout/pop over - it should probably use a 4px Corner Radius, but yea, only @chigy would know for sure

The flyout of the NavigationView's overflow button in Top mode is also missing rounded corners:
image

As it is a flyout/pop over - it should probably use a 4px Corner Radius, but yea, only @chigy would know for sure

@mdtauk , that is right.

If no one else is working/wants to work on this and this is confirmed to be an oversight, I would like to fix this.

@Felix-Dev You can pick this up. Thanks !

If no one else is working/wants to work on this and this is confirmed to be an oversight, I would like to fix this.

@Felix-Dev You can pick this up. Thanks !

There should be a Style resource you can use to give it the correct corner radius, so the value can be changed by the developer if they wish to, and it keeps it consistent with the other controls

I think it should use the OverlayCornerRadius resource.

@mdtauk The resource I would use is the OverlayCornerRadius one which has been introduced for UI elements like these. It would resolve to a 4px corner radius.

I think it should use the OverlayCornerRadius resource.

Thanks, I couldn't recall the resource name

@ranjeshj I modified the flyout XAML from

<Style TargetType="FlyoutPresenter">
    <Setter Property="Padding" Value="0,8" />
    <Setter Property="Margin" Value="0,-4,0,0" />
</Style>

to

<Style TargetType="FlyoutPresenter">
    <Setter Property="Padding" Value="0,8" />
    <Setter Property="Margin" Value="0,-4,0,0" />
    <contract7Present:Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="FlyoutPresenter">
                <ContentPresenter Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Content="{TemplateBinding Content}"
                    ContentTemplate="{TemplateBinding ContentTemplate}"
                    ContentTransitions="{TemplateBinding ContentTransitions}"
                    Padding="{TemplateBinding Padding}"
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                    contract7Present:CornerRadius="{TemplateBinding CornerRadius}"
                    contract7NotPresent:CornerRadius="{ThemeResource OverlayCornerRadius}"/>
                </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

For an ItemsRepeater as the flyout content this causes the following effect:

Before change:
image

After change:
image

I have tested flyout content such as a single TextBox or a ListView and in both cases, the flyout has the same width, no matter if I set the FlyoutPresenter's ControlTemplate or not. It's only the ItemsRepeater for now where I noticed this behavior. Is this expected?

(I am setting the ControlTemplate in the style as the FlyoutPresenter.CornerRadius property is only available since Windows 10 1809. Thus, in order to have a rounded flyout on older Windows versions, I am directly setting the border radius of the ContentPresenter to the OverlayCornerRadius resource in the ControlTemplate.)

@chigy Could you confirm if the corner radius of the Overflow menu in Top mode (https://github.com/microsoft/microsoft-ui-xaml/issues/2401#issuecomment-625391360) also needs to be changed to the OverlayCornerRadius value?

@Felix-Dev , I'm a bit confused by the before/after shot. Why is the menu wider? I assume that's what you are asking @ranjeshj , but wanted to double check.

@chigy Could you confirm if the corner radius of the Overflow menu in Top mode (#2401 (comment)) also needs to be changed to the _OverlayCornerRadius_ value?

@Felix-Dev , yes all 4 corners should be rounded since they are not connected to the bar.

@chigy Yes, that's exactly what I'm asking @ranjeshj.

PS: If needed, I can create a repro app showcasing this behavior.

@Felix-Dev sorry for the delayed response. I don't see any reason why ItemsRepeater would be different in this case. @ojhad any ideas what might be happening here ?

@ranjeshj @ojhad I have created a repro app:
FlyoutControlTemplateItemsRepeaterIssue.zip

App example image:
image

The buttons with "Flyout with [...] (custom CP)" use the custom ContentPresenter styling shown above (so that corner radius can be applied):

<Style TargetType="FlyoutPresenter">
    <Setter Property="Padding" Value="0,8" />
    <Setter Property="Margin" Value="0,0,0,0" />
    <contract7Present:Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="FlyoutPresenter">
                <ContentPresenter Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Content="{TemplateBinding Content}"
                    ContentTemplate="{TemplateBinding ContentTemplate}"
                    ContentTransitions="{TemplateBinding ContentTransitions}"
                    Padding="{TemplateBinding Padding}"
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                    contract7Present:CornerRadius="{TemplateBinding CornerRadius}"
                    contract7NotPresent:CornerRadius="{ThemeResource OverlayCornerRadius}"/>
                </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The two other buttons just use the current FlyoutPresenter style used in NavigationView.xml (with no corner radius applied):

<Style TargetType="FlyoutPresenter">
    <Setter Property="Padding" Value="0,8" />
    <Setter Property="Margin" Value="0,0,0,0" />
</Style>

Observe that the resulting flyouts look the same for both buttons with a ListView as Flyout content, whereas the resulting flyouts of the buttons with an ItemsRepeater as Flyout content differ quite a bit. More precisely, the flyout with the custom ContentPresenter

  • is much wider
  • displays only the first item instead of all three

I used the CalendarDatePicker FlyoutPresenter as reference here: https://github.com/microsoft/microsoft-ui-xaml/blob/c5fa8a6b45efe820b80aa994751801df553117f7/dev/CalendarDatePicker/CalendarDatePicker_themeresources.xaml#L186

@Felix-Dev Thanks for putting together the repro app. This seems related to this issue. where Repeater does not know how to get the viewport correctly when parented under a popup/flyout. The workaround is to add the ScrollHost/ScrollViewer. ListView has a ScrollViewer in its template, so this is closer to what ListView does under the covers.

<Button Content="Flyout with ItemsRepeater" Margin="0,0,10,0">
                <Button.Flyout>
                    <Flyout FlyoutPresenterStyle="{StaticResource FlyoutPresenterStyleWithoutCustomContentPresenter}">
                        <muxc:ItemsRepeaterScrollHost>
                            <ScrollViewer VerticalScrollBarVisibility="Auto">
                                <muxc:ItemsRepeater ItemsSource="{x:Bind Items}">
                                    <muxc:ItemsRepeater.Layout>
                                        <muxc:StackLayout Orientation="Vertical" Spacing="10"/>
                                    </muxc:ItemsRepeater.Layout>
                                </muxc:ItemsRepeater>
                            </ScrollViewer>
                        </muxc:ItemsRepeaterScrollHost>
                    </Flyout>
                </Button.Flyout>
            </Button>

@ranjeshj Thanks for taking a look. While that fixes the issue with only the first item showing up, it seems we still have the issue where the resulting flyout is much wider when explicitly using a ContentPresenter in the FlyoutPresenterStyle than without:
image
(You can see that in repro app when clicking on the "Flyout with ItemsRepeater (custom CP)" button. The button "Flyout with ItemsRepeater" shows the presumably correct flyout width.)

@Felix-Dev The default style for FlyoutPresenter works, so I'm guessing that some combination of properties is causing this. You could start with the default style and start trimming it down from that (like below, I just added the corner radius properties on top of the default style)

 <Style TargetType="FlyoutPresenter"  x:Key="FlyoutPresenterStyleWithCustomContentPresenter" >
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="VerticalContentAlignment" Value="Stretch" />
            <Setter Property="IsTabStop" Value="False" />
            <Setter Property="Background" Value="{ThemeResource FlyoutPresenterBackground}" />
            <Setter Property="BorderBrush" Value="{ThemeResource FlyoutBorderThemeBrush}" />
            <Setter Property="BorderThickness" Value="{ThemeResource FlyoutBorderThemeThickness}" />
            <Setter Property="Padding" Value="{ThemeResource FlyoutContentThemePadding}" />
            <Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
            <Setter Property="MaxWidth" Value="{ThemeResource FlyoutThemeMaxWidth}" />
            <Setter Property="MinHeight" Value="{ThemeResource FlyoutThemeMinHeight}" />
            <Setter Property="MaxHeight" Value="{ThemeResource FlyoutThemeMaxHeight}" />
            <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
            <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
            <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
            <Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="FlyoutPresenter">
                        <Border
              Background="{TemplateBinding Background}"
              BackgroundSizing="OuterBorderEdge"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}"
              CornerRadius="{TemplateBinding CornerRadius}"
              Padding="{ThemeResource FlyoutBorderThemePadding}">
                            <ScrollViewer x:Name="ScrollViewer"
                ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
                HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                AutomationProperties.AccessibilityView="Raw">
                                <ContentPresenter Content="{TemplateBinding Content}"
                  ContentTemplate="{TemplateBinding ContentTemplate}"
                  ContentTransitions="{TemplateBinding ContentTransitions}"
                  Margin="{TemplateBinding Padding}"
                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                   contract7Present:CornerRadius="{TemplateBinding CornerRadius}"
                            contract7NotPresent:CornerRadius="{ThemeResource OverlayCornerRadius}"/>
                            </ScrollViewer>
                        </Border>

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

@ranjeshj Thanks for taking another look. Looks like this style will do it:

<Style TargetType="FlyoutPresenter">
    <Setter Property="Padding" Value="{ThemeResource NavigationViewItemChildrenMenuFlyoutPadding}" />
    <!-- Set negative top margin to make the flyout align exactly with the button -->
    <Setter Property="Margin" Value="0,-4,0,0" />
    <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
    <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
    <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
    <contract7Present:Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="FlyoutPresenter">
                <ScrollViewer
                    x:Name="ScrollViewer"
                    ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
                    HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                    HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                    VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                    VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                    AutomationProperties.AccessibilityView="Raw">
                    <ContentPresenter
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Content="{TemplateBinding Content}"
                        ContentTemplate="{TemplateBinding ContentTemplate}"
                        ContentTransitions="{TemplateBinding ContentTransitions}"
                        Padding="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                        contract7Present:CornerRadius="{TemplateBinding CornerRadius}"
                        contract7NotPresent:CornerRadius="{ThemeResource OverlayCornerRadius}"/>
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

image

(The flyout shadow doesn't show up in the screenshot but it's there.)

Was this page helpful?
0 / 5 - 0 ratings