View Issue Details

IDProjectCategoryView StatusLast Update
0002474NoesisGUIC# SDKpublic2023-04-24 17:45
Reportersumel007 Assigned Tosfernandez  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.1.6 
Target Version3.1.7Fixed in Version3.2.1 
Summary0002474: KeyboardNavigation parameters are ignored in StackPanel and Dockpanel
DescriptionWhen I have a stackpanel with KeyboardNavigation.DirectionalNavigation="Contained" keyboard focus still escapes outside the stackpanel contents (even though it doesn't happen in WPF). Similar things happen to TabNavigation.
Steps To ReproduceI've modified StartMenu.xaml in 3DMenu sample, but you should be able to reproduce this by creating a stackpanel with keyboard navigation and another control outside the staxckpanel.

<Grid x:Name="MenuOptions" Grid.Row="1" Width="640" Margin="0,30,0,0" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5"
                 VerticalAlignment="Top" Height="300">
                    <Grid.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform/>
                            <SkewTransform/>
                            <RotateTransform/>
                            <TranslateTransform/>
                        </TransformGroup>
                    </Grid.RenderTransform>
                    <StackPanel KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Contained">
                        <Rectangle Height="2" Margin="0,0,0,2" Fill="{StaticResource HorizontalLineBg}"/>
                        <ToggleButton x:Name="Casual" Style="{StaticResource MenuButtonStyle}" Content="CASUAL" Command="{Binding StartCasual}"/>
                        <ToggleButton x:Name="Normal" Style="{StaticResource MenuButtonStyle}" Content="NORMAL" Command="{Binding StartNormal}"/>
                        <ToggleButton x:Name="Expert" Style="{StaticResource MenuButtonStyle}" Content="EXPERT" Command="{Binding StartExpert}"/>

                    </StackPanel>
                    <ToggleButton VerticalAlignment="Bottom" Style="{StaticResource MenuButtonStyle}" Content="reee" Command="{Binding StartCasual}" Height="48"/>

                </Grid>
TagsNo tags attached.
PlatformWindows

Activities

sumel007

sumel007

2023-04-06 15:05

reporter   ~0008409

Is there any more news on this issue? It seems that even with popups (at least in 3.2) when we have a popup with KeyboardNavigation.DirectionalNavigation="Contained" and KeyboardNavigation.TabNavigation="Contained" focus can escape behind the popup, making keyboard focus management very cumbersome.
sfernandez

sfernandez

2023-04-11 11:55

manager   ~0008410

Hi, I tried to reproduce this problem with 3.1.6, 3.1.7, and 3.2.0 without success.
When I set the DirectionalNavigation and TabNavigation to Contained in the StackPanel in the Menu3D sample, and the focus is inside that StackPanel, I cannot move the focus out of the panel just by using the arrows/gamepad or the tab key.
I even created the following xamltoy, and it works as expected: https://www.noesisengine.com/xamltoy/75228d301d0d9f9753efba5984a9ff1a

Regarding the Popup, by default it doesn't override the directional or tab navigation, so the focus can go outside the Popup. But you can just set the navigation mode in the popup root to keep it inside:

<Grid 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Grid x:Name="MenuOptions" Grid.Row="1" Width="640" Margin="0,30,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="300" Background="Pink">
    <Popup IsOpen="True" Placement="Center">
      <Grid Width="300" Height="200" Background="LightBlue" 
                 KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Contained">
        <StackPanel>
            <Rectangle Height="2" Margin="0,0,0,2" Fill="Silver"/>
            <ToggleButton x:Name="Casual" Content="CASUAL" Command="{Binding StartCasual}"/>
            <ToggleButton x:Name="Normal" Content="NORMAL" Command="{Binding StartNormal}"/>
            <ToggleButton x:Name="Expert" Content="EXPERT" Command="{Binding StartExpert}"/>
        </StackPanel>
        <ToggleButton VerticalAlignment="Bottom" Content="Inside Popup" Command="{Binding StartCasual}" Height="48"/>
      </Grid>
    </Popup>
    <ToggleButton VerticalAlignment="Bottom" Content="Outside Popup" Height="48"/>
  </Grid>
</Grid>
sumel007

sumel007

2023-04-12 12:03

reporter   ~0008415

Last edited: 2023-04-12 12:03

I've retested the sample I've provided and it seems that it does indeed work correctly. Sorry for that, I am quite confused as to how that happened. The problem remains within our project, But it seems to only happen to TabNavigation.

 I tried to recreate the situation from our project without having to provide all the files, so the xaml is quite chaotic. I am attaching it to this note (I just removed the contents of MainWindow.xaml from Menu3D and tried to set up a similar situation to our project). Now when the middle portion (which imitates a popup, so it's very improtant there's absolutely no way to focus anything below that) with left/right buttons gets focus we cannot escape it via arrow keys (which is correct, since that DockPanel has KeyboardNavigation.DirectionalNavigation="Contained"). However we can escape outside that dockpanel via Tab key once the focus is on the "RightButton", even though we've set KeyboardNavigation.TabNavigation="Contained". Now it seems to behave this way in both WPF and Noesis with one exception - WPF immediately switches focus to the button to the right ("Settings") whereas Noesis first loses focus completely and then the next keypress focuses on the Settings button. So I assume this is a bug on Noesis part. But WPF behaviour doesn't fix the issue for me either.

The behaviour I would want however is different from both WPF and Noesis - that is I want TabNavigation to remain within the popup. If I set TabNavigation="None" that still doesn't happen - it only changes so that the buttons inside will not get navigated to via tab navigation, but once they have focus it can still escape via tab.
For now I guess I could just handle PreviewKeyDown and mark it as handled, so the tab navigation never happens, but I'm wondering if there's a better way. Especially since in your example it seems to behave as expected, whereas in mine even with TabNavigation=Contained it isn't contained to that panel.
sumel007

sumel007

2023-04-12 12:04

reporter   ~0008416

MainWindow.xaml (4,771 bytes)   
<Window x:Class="Menu3D.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:Menu3D"
    xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
    Title="NoesisGUI - Menu3D"
    FontFamily="Fonts/#WeblySleek UI Semilight"
        Height="1080" Width="1920">
    <Window.Resources>
        <Style x:Key="CustomFocusStyle">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Control">
                        <Border BorderThickness="5" BorderBrush="#FF0000" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource CustomFocusStyle}" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid Margin="80,150,80,100">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="573"/>
            </Grid.ColumnDefinitions>
            <DockPanel Grid.Column="1" Margin="10,10,10,10" >
                <Button 
                    Content="Settings" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" DockPanel.Dock="Top" Width="365"   
                   />
            </DockPanel>
            <Button 
                    Content="New Game"
                  Margin="10,10,0,10" HorizontalAlignment="Left" Width="375"
                   />
        </Grid>
        <StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Top" Margin="0,50,80,0">

        </StackPanel>

        <Button Height="32" FontSize="17.6" Margin="80,0,0,50" VerticalAlignment="Bottom" HorizontalAlignment="Left" x:Name="BackButton" Content="EXIT"  >
        </Button>

        <Button Visibility="Visible" Height="32" FontSize="17.6" Margin="499.8,0,0,50" VerticalAlignment="Bottom" HorizontalAlignment="Left"   Content="Debug Skip to my career" 
         >
        </Button>

        <StackPanel Background="Black" x:Name="PopupImitator" HorizontalAlignment="Center" Orientation="Vertical" VerticalAlignment="Center">

            <Canvas Height="50" Background="#0F0">
                <Canvas.Clip>
                    <RectangleGeometry RadiusX="10"
                                 RadiusY="10"                           
                                 Rect="0,0,772,200"/>
                </Canvas.Clip>
                <Canvas.Resources/>

            </Canvas>

            <Border x:Name="Pop_Up" Background="#CCFFFFFF" Padding="30,30,30,30" CornerRadius="0,0,10,10">
                <StackPanel Orientation="Vertical" Width="672">

                    <StackPanel Orientation="Horizontal" Width="672" Margin="0,0,0,30">
                        <Viewbox Width="130" Height="130" Margin="0,0,10,0">
                            <Border Padding="2,2,2,2">

                            </Border>

                        </Viewbox>
                        <TextBlock x:Name="Head"
                        Width="532"
                        Foreground="White"
                        
                        Text="WOULD YOU LIKE TO OVERWRITE THE SAVE GAME?" VerticalAlignment="Center"/>

                    </StackPanel>
                    <TextBlock Margin="0,0,0,30" x:Name="SubHeadPop"

                    Foreground="Yellow"
                   
                    Text="ALL OVERWRITTEN PROGRESS WILL BE LOST."/>
                    <TextBlock x:Name="BodyPop"

                    Foreground="Yellow"
                   
                    Text="I will be updating this document. If you have any ideas, comments or z else please contact mez via discord - Adam Jedrzejewski or Vasqes. Your feedback is very important and I would love to hear it! Thank you! 👍😁"/>
                </StackPanel>

            </Border>
            <Border >
                <DockPanel KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="None" >
                    <Button  Margin="0,0,30,0" x:Name="LeftButton"  Content="LeftBt" />
                    <Button  x:Name="RightButton"  Content="RightButton"  />
                </DockPanel>

            </Border>
        </StackPanel>
    </Grid>
</Window>
MainWindow.xaml (4,771 bytes)   
MainWindow.xaml.cs (1,249 bytes)   
#if NOESIS
using Noesis;
using NoesisApp;
#else
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
#endif

namespace Menu3D
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            System.WeakReference wr = new System.WeakReference(this);
            this.Loaded += (s, e) => { ((MainWindow)wr.Target).OnLoaded(s, e); };
            this.SizeChanged += (s, e) => { ((MainWindow)wr.Target).OnSizeChanged(s, e); };

            this.InitializeComponent();
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            //DataContext = new ViewModel();
        }

        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {

        }

#if NOESIS
        private void InitializeComponent()
        {
            Noesis.GUI.LoadComponent(this, "/Menu3D;component/MainWindow.xaml");
        }

        StackPanel SkyAndSun;
        StackPanel Mountains;
        StackPanel FrontTrees;
        StackPanel BackClouds;
        StackPanel FrontClouds;
#endif
    }
}
MainWindow.xaml.cs (1,249 bytes)   
sfernandez

sfernandez

2023-04-24 13:43

manager   ~0008453

Last edited: 2023-04-24 17:44

I've been anaylizing how WPF behaves with TabNavigation="Contained" and for me it seems bugged, because it is not moving the focus as described in the documentation:

    public enum KeyboardNavigationMode
    {
        /// <summary>
        /// The container does not handle the keyboard navigation;
        /// each element receives keyboard focus as long as it is a key navigation stop.
        /// </summary>
        Continue,
 
        /// <summary>
        /// The container and all of its child elements as a whole only receive focus once.
        /// Either the first tree child or the ActiveElement receive focus
        /// </summary>
        Once,
 
        /// <summary>
        /// Depending on the direction of the navigation,
        /// the focus returns to the first or the last item when the end or
        /// the beginning of the container is reached, respectively.
        /// </summary>
        Cycle,
 
        /// <summary>
        /// No keyboard navigation is allowed inside this container
        /// </summary>
        None,
 
        /// <summary>
        /// Like cycle but does not move past the beginning or end of the container.
        /// </summary>
        Contained,
 
        /// <summary>
        /// TabIndexes are considered on local subtree only inside this container
        /// </summary>
        Local
    }


However, with DirectionalNavigation="Contained" the behavior seems correct, when you reach the end of the container it stops the focus there, and cannot be moved outside.

We decided to fix the implementation in TabNavigation to behave like DirectionalNavigation, so focus won't move outside the container.

Issue History

Date Modified Username Field Change
2022-12-06 11:23 sumel007 New Issue
2022-12-07 01:50 jsantos Assigned To => sfernandez
2022-12-07 01:50 jsantos Status new => assigned
2022-12-07 01:51 jsantos Target Version => 3.1.7
2023-04-06 15:05 sumel007 Note Added: 0008409
2023-04-07 12:06 sumel007 Severity minor => major
2023-04-11 11:55 sfernandez Status assigned => feedback
2023-04-11 11:55 sfernandez Note Added: 0008410
2023-04-12 12:03 sumel007 Note Added: 0008415
2023-04-12 12:03 sumel007 Status feedback => assigned
2023-04-12 12:03 sumel007 Note Edited: 0008415
2023-04-12 12:04 sumel007 Note Added: 0008416
2023-04-12 12:04 sumel007 File Added: MainWindow.xaml
2023-04-12 12:04 sumel007 File Added: MainWindow.xaml.cs
2023-04-24 13:43 sfernandez Status assigned => feedback
2023-04-24 13:43 sfernandez Note Added: 0008453
2023-04-24 13:44 sfernandez Note Edited: 0008453
2023-04-24 17:44 sfernandez Note Edited: 0008453
2023-04-24 17:44 sfernandez Note Edited: 0008453
2023-04-24 17:45 sfernandez Status feedback => resolved
2023-04-24 17:45 sfernandez Resolution open => fixed
2023-04-24 17:45 sfernandez Fixed in Version => 3.2.1