Search code examples
uwpaccessibilitytabstopkeyboard-focus

Set keyboard interaction focus to a MenuFlyoutItem


In a UWP app I have used MenuFlyoutItem to show drop down list. Here is xaml code

    <DropDownButton Style="{StaticResource DropDownButtonStyle1}" Name="MyDropDownButton" 
                Content="{Binding SelectedLanguage}" 
                RelativePanel.AlignRightWithPanel="True" 
                Margin="0,20,20,0" 
                FontSize="14">
        <DropDownButton.Flyout>
            <MenuFlyout x:Name="OptionMenu"
                        Placement="BottomEdgeAlignedRight">
            </MenuFlyout>
        </DropDownButton.Flyout>
    </DropDownButton>

Programmatically i am adding MenuFlyoutItem to MenuFlyout

foreach (Option option in _viewModel.Options)
{
    MenuFlyoutItem item = new MenuFlyoutItem();
    item.Text = option.text;
    LanguagesMenu.Items.Add(item);
}

Problem: When user use app with keyboard interaction the first MenuFlyoutItem is focused. I want different item to get focused (may be user previously selected item should get focused).

Example:

I have 3 option:

  1. Left
  2. Right
  3. Bottom

When user open MenuFlyout by keyboard Enter its by default focused first item -> Left. I want 2nd item -> Right to be focused.

How can i achieve this. I have read this Keyboard Interaction official doc but didn't find any idea.


Solution

  • You could directly use the Control.Focus(FocusState) Method to make the MenuFlyoutItem go to the focus state. I suggest you do this in the Flyout.Opened Event.

    Based on your code, I made a simple demo and you might check it.

    Xaml:

      <DropDownButton.Flyout>
                <MenuFlyout x:Name="OptionMenu"  Placement="BottomEdgeAlignedRight" Opened="OptionMenu_Opened">
                </MenuFlyout>
            </DropDownButton.Flyout>
    

    Code behind:

    private void OptionMenu_Opened(object sender, object e)
        {
            // let's say we need to set the seconed item as focused
            var list = OptionMenu.Items;
            MenuFlyoutItem item2 = list[1] as MenuFlyoutItem;
    
            item2.Focus(FocusState.Keyboard);
        }
    

    Update:

    Only make the item focused when the Enter key is pressed.

    public Boolean IsKeyPressed = false;
    
      private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // same code 
            MenuFlyoutItem item = new MenuFlyoutItem();
            item.Text = "Left";
    
            MenuFlyoutItem item2 = new MenuFlyoutItem();
            item2.Text = "Right";
    
            MenuFlyoutItem item3 = new MenuFlyoutItem();
            item3.Text = "Bottom";
    
            OptionMenu.Items.Add(item);
            OptionMenu.Items.Add(item2);
            OptionMenu.Items.Add(item3);
            // handle the button keydown event.
            MyDropDownButton.PreviewKeyDown += MyDropDownButton_PreviewKeyDown;
        }
    
        private void MyDropDownButton_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
        {
            //check if it is the Enter key
            if (e.Key == VirtualKey.Enter)
            {
                IsKeyPressed = true;
                Debug.WriteLine("Enter");
            }
            else 
            {
                return;
            }
        }
    
        private void OptionMenu_Opened(object sender, object e)
        {
            Debug.WriteLine("Open");
    
            if (IsKeyPressed) 
            {
                // let's say we need to set the seconed item as focused
                var list = OptionMenu.Items;
                MenuFlyoutItem item2 = list[1] as MenuFlyoutItem;
    
                item2.Focus(FocusState.Keyboard);
                //reset the flag  
                // You could do this in other places if you want.
                IsKeyPressed = false;
            }
           
        }