How can I override or act on KeyDown: Space or Enter for ListView in UWP?
Asked Answered
K

4

5

I've attached the KeyDown event to a ListView in my Win 10 UWP app. I want to make VirtualKey.Enter have a special effect, but the event is not firing for this particular key. Neither does it for Space, Arrow up or down. This I guess because the listview already has defined a special behaviour for those keys.

I'd like to override some of those keys though, or at least trigger additional actions. Even attaching events to those key with modifiers (e.g. Shift+ArrowDown) would not work because the events still are not firing.

I read that for WPF that there is a PreviewKeyDown-event which one can attach to. I can't find that event for UWP though. Are there any other options?

Knave answered 22/5, 2016 at 16:1 Comment(4)
Are you genuinely interested in those keypresses, or do you want to modify the standard behavior, those keypresses trigger in the control?Wow
I'm interested in the key presses. For space i want to invoke an action instead of deselect the item. For arrow left and right I also want to invoke an actionKnave
In these cases I usually attach the event on the parent control, then check if the focused control is which I'm looking for and then execute the desired logic. I don't know any other workaround for this on UWP.Wivern
For info...PreviewKeyDown is now available in UWPAlternate
H
1

Here is one way to do it : subscribe to the global Window.Current.CoreWindow.KeyDown event. Then save the focus state of your listview and react accordingly.

Here is the code :

public sealed partial class MainPage : Page
{
    bool hasFocus = false;
    public MainPage()
    {
        this.InitializeComponent();
        Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
    }

    private void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
    {
        if(hasFocus)
        {
            Debug.Write("Key down on list");
        }
    }

    private void myList_GotFocus(object sender, RoutedEventArgs e)
    {
        hasFocus = true;

    }

    private void myList_LostFocus(object sender, RoutedEventArgs e)
    {
        hasFocus = false;
    }

You will also need to subscribe to the focus events in xaml, for your ListView :

<ListView .... GotFocus="myList_GotFocus" LostFocus="myList_LostFocus"/>
Hukill answered 23/5, 2016 at 13:22 Comment(3)
Thanks! That solved the problem for Space, Up and Down, but Enter is still not firing. Any idea why? Not that it's a big issue, I can live without Enter. Maybe there are some other events triggering with Enter.Knave
Note: Adding an event handler for a parent UI object the normal way as also suggested will not work since events are bubbled up, not down. I found this documentation that goes into detail and also describes how to work around it msdn.microsoft.com/en-us/windows/uwp/xaml-platform/…Knave
@Stephanie It would be better to subscribe to the event in OnNavigatedTo or OnLoaded and of course remember to unsubscribe in OnNavigatedFromSteere
S
5

Stephanie's answer is a good one and it works in the general case. However, as Nilzor observed it will not work in the case of a ListView for the Enter key. For some reason the ListView handles the KeyDown event in case Enter is pressed.

A better way to handle key events when dealing with a ListView, as the question asks, is this.

 private void ListView_Loaded(object sender, RoutedEventArgs e)
    {
        (sender as ListView).AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(ListView_KeyDown), true);
    }

 private void ListView_KeyDown(object sender, KeyRoutedEventArgs args)
    {
        if (args.Key == Windows.System.VirtualKey.Enter)
        {

        }
    }

Notice the last argument in the AddHandler function. This specifies whether we want to handle events already handled by a previous element in the visual tree. Of course don't forget to unsubscribe from the event when appropriate

Steere answered 2/6, 2017 at 15:35 Comment(1)
Thank you so much for adding this answer! I completely forgot about this technique, and it solve my issue. I was trying to attach a KeyDown handler for a UWP Button to capture Enter and Space, and did not want to process them in a Click handler (which captures the Enter and Space keys automatically). This is definitely the right solution for this question.Darius
H
1

Here is one way to do it : subscribe to the global Window.Current.CoreWindow.KeyDown event. Then save the focus state of your listview and react accordingly.

Here is the code :

public sealed partial class MainPage : Page
{
    bool hasFocus = false;
    public MainPage()
    {
        this.InitializeComponent();
        Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
    }

    private void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
    {
        if(hasFocus)
        {
            Debug.Write("Key down on list");
        }
    }

    private void myList_GotFocus(object sender, RoutedEventArgs e)
    {
        hasFocus = true;

    }

    private void myList_LostFocus(object sender, RoutedEventArgs e)
    {
        hasFocus = false;
    }

You will also need to subscribe to the focus events in xaml, for your ListView :

<ListView .... GotFocus="myList_GotFocus" LostFocus="myList_LostFocus"/>
Hukill answered 23/5, 2016 at 13:22 Comment(3)
Thanks! That solved the problem for Space, Up and Down, but Enter is still not firing. Any idea why? Not that it's a big issue, I can live without Enter. Maybe there are some other events triggering with Enter.Knave
Note: Adding an event handler for a parent UI object the normal way as also suggested will not work since events are bubbled up, not down. I found this documentation that goes into detail and also describes how to work around it msdn.microsoft.com/en-us/windows/uwp/xaml-platform/…Knave
@Stephanie It would be better to subscribe to the event in OnNavigatedTo or OnLoaded and of course remember to unsubscribe in OnNavigatedFromSteere
A
1

Corcus's solution doesn't work for me. What is working is handling PreviewKeyDown directly from XAML. Works well for SPACE or ENTER key:

XAML:

<ListView PreviewKeyDown="BookmarksListView_PreviewKeyDown">

Code behind:

private void BookmarksListView_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.Enter)
    {
        // DO YOUR STUFF...
        e.Handled = true;
    }
}
Anarchic answered 7/4, 2020 at 23:15 Comment(0)
O
0

You can use AddHandler method.

private void KeyEnterEventHandler(object sender, KeyRoutedEventArgs e)
    {
        if (e.OriginalKey == Windows.System.VirtualKey.Enter)
        {
            PlayFromListView();
        }
    }
    private void LoadListView()
    {
        foreach (var music in playListStorageFile.PlayList)
        {
            ListViewItem item = new ListViewItem();
            item.AddHandler(FrameworkElement.KeyDownEvent, new KeyEventHandler(KeyEnterEventHandler), true);

            TextBlock mytext = new TextBlock();
            mytext.Text = music.Nro.ToString() + " - " + music.Name;
            mytext.Tag = music.Nro;
            item.Content = mytext;
            lvMusics.Items.Add(item);
        }
    }

https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.uielement.addhandler?view=winrt-18362

Ornithine answered 1/5, 2020 at 21:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.