I'm trying to capture keypress events anywhere in my WPF application, regardless of which UI element has the focus. Currently I'm having no luck. Can anyone suggest some strategies that I might not have tried? Or, ideally, provide an answer like "oh that's easy, you just do this".
It's a distributed application, which has a chat system. The effect that I'm looking for is that the user can start typing a chat message at any time, without switching to a standard chat box. I'll display their message in the application myself, using FormattedText objects. This is important because it means there are no text input elements in the application anywhere.
My XAML structure looks roughly like:
<MainWindow>
<Canvas 1>
<Canvas 2>
<Image 1 />
</Canvas 2>
<Image 2 />
</Canvas 1>
</MainWindow>
I programmatically add elements into Canvas 2, and manipulate Image 2, which is why it has that structure.
I've tried adding KeyDown, KeyUp and the Preview events to MainWindow and Canvas 1, but none of them seem to fire (I check with breakpoints). I've also, after reading another related question here, tried manually setting the focus on the main window in the Loaded() method.
I realise there are many related questions on this site, but they haven't helped me because:
Thank you for taking the time to read my long winded post, and thank you for suggestions.
Update (After Rachel's comment) When I put in a TextBox and set the focus to the TextBox, a key event method at the MainWindow level will fire. So that works as advertised.
However, I would really like to not have an explicit text entry widget in the application at all. I would like the user to be able to just start typing to compose a message.
A little bit of tinkering got me this:
XAML:
<Window x:Class="KeyInput.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="225">
<Canvas>
<Grid>
<Label Name="test" Content="Empty" />
</Grid>
</Canvas>
</Window>
CS:
using System.Windows;
using System.Windows.Input;
namespace KeyInput
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(OnButtonKeyDown);
}
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
test.Content = test.Content + e.Key.ToString();
}
}
}
This prints out stuff like "Shift" So you'd obviously have to use switches... but it has a Text Box that collects key presses.
I managed to work it out, inspired by answers from Rachel and WernerCD. As they both demonstrated, having the event capture at the MainWindow level does work. The problem was that I neglected to mention that I had a dialog before the MainWindow loaded, which seems to interfere with normal keyboard focus on the MainWindow. Putting explicit Keyboard.focus() in the Loaded() method is too soon. I fixed the problem by putting Keyboard.focus() in the MainWindow_ContentRendered() method.
All is now well (until the next issue anyway). Thank you for the help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With