WPF keyboard events not firing for FrameworkElement subclass with only visuals

483 Views Asked by At

I created a subclass of FrameworkElement that has a collection of Visuals :

public class GameElement : FrameworkElement
{
    private VisualCollection Visuals { get; }

    public GameElement()
    {
        this.KeyDown += this.OnKeyDown;
        this.MouseDown += this.OnMouseDown;
    }

    private void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
    {
        ... // Does not get fired.
    }

    private void OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        ... // Does get fired.
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        // Draw a transparent background to catch mouse events (otherwise hit testing won't hit anything).
        drawingContext.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
    }

    protected override int VisualChildrenCount
    {
        get
        {
            return this.Visuals.Count;
        }
    }

    protected override Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= this.Visuals.Count)
        {
            throw new ArgumentOutOfRangeException();
        }

        return this.Visuals[index];
    }
}

I display this element in XAML with the following code :

<UserControl
    x:Class="..."
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Background="Black">

    <Grid Margin="10">
        <local:GameElement x:Name="GameElement" ClipToBounds="True" />
    </Grid>
</UserControl>

I have tried everything I can think of, but I just cannot get the KeyDown event to fire. The mostly used comment I find online has to do with focus. I have tried every combination of Focusable="True" and calling this.Focus(), but nothing works.

Anyone got any idea how to do this? Thanks!

2

There are 2 best solutions below

0
Yevgeniy On

To be able to handle keys pressing your element should be focused. Also try to derive it from control instead of FramworkElement if you can do that.

public class GameElement : Control
{
    private VisualCollection Visuals { get; }

    public GameElement()
    {
        this.KeyDown += this.OnKeyDown;
        this.MouseDown += this.OnMouseDown;
    }

    private void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
    {
        // Does get fired.
    }

    private void OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        Focus();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        // Draw a transparent background to catch mouse events (otherwise hit testing won't hit anything).
        drawingContext.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
    }

    protected override int VisualChildrenCount
    {
        get
        {
            return this.Visuals.Count;
        }
    }

    protected override Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= this.Visuals.Count)
        {
            throw new ArgumentOutOfRangeException();
        }

        return this.Visuals[index];
    }
}
0
Filip Van Bouwel On

I finally got it to work by registering a class handler that also handles handled events.

EventManager.RegisterClassHandler(typeof(Window), Keyboard.KeyDownEvent, new KeyEventHandler(OnKeyDown), true);