2

I'm currently working on a little game as a WinForms project. The gamefield is build out of a grid of Tiles a Player (a separate class) can move on. I want the player to move with the arrow keys and have set up an event handler for it, but it doesn't seem to be ever called.

(minimalized) player class, which implements the System.Windows.Forms packages for the KeyEventArgs:

public class Player : MovableObject
{
    public Player(Playtile position) : base(position)
    {
        EntityColor = ElementColors.PlayerColor;
        PostConstructor(position);
    }

    /// <summary>
    /// Reads keypress via eventhandler KeyEventArgs (key down). 
    /// </summary>
    private void ReadKeyDown(object sender, KeyEventArgs e)
    {
        switch (e.KeyCode)
        {
            case Keys.Up:
                // move up.
                break;
            case Keys.Right:
                // move right.
                break;
            case Keys.Down:
                // move down.
                break;
            case Keys.Left:
                // move left.
                break;
        }
    }
}

Currently, the ReadKeyDown never gets called. How do I actually assign / bind that KeyEventDown event to the player, so it actually calls that method on key down?

KeyEventArgs in C# seems to simply say this.KeyDown += ReadKeyDown;, but it doesn't recognize KeyDown as anything, nor does it give me a possible missing assembly reference.

aybe
  • 15,516
  • 9
  • 57
  • 105
Sander Koldenhof
  • 1,223
  • 4
  • 13
  • 26

2 Answers2

1

KeyDown is a member of Control so in your case you could subscribe to that event in your Form.

Like the following:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
        textBox1.KeyDown += TextBox1_KeyDown;
    }

    private void TextBox1_KeyDown(object sender, KeyEventArgs e)
    {
    }
}

See the official documentation for a complete example:

https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.keydown?view=netframework-4.7.2

Now what you could do is invoke a method in your target class once you've received such event:

public class MyClass
{
    public void OnKeyDown(KeyEventArgs e)
    {
        // ...
    }
}

public partial class Form2 : Form
{
    MyClass _instance = new MyClass();

    public Form2()
    {
        InitializeComponent();
        textBox1.KeyDown += TextBox1_KeyDown;
    }

    private void TextBox1_KeyDown(object sender, KeyEventArgs e)
    {
        _instance.OnKeyDown(e);
    }
}
aybe
  • 15,516
  • 9
  • 57
  • 105
0

You could subscribe to the KeyDown event directly in your class:

public Player(Playtile position, Form form) : base(position) // <--- form parameter
{
    EntityColor = ElementColors.PlayerColor;
    PostConstructor(position);
    form.KeyDown += ReadKeyDown; // <--- subscribing to the event
}

There is an issue though. Now the form holds a reference to your Player object, and the object will not be garbage collected until the form is closed. This is not a problem if the Player's lifespan is the same with the form's lifespan. But if you create many short-lived players then you should unsubscribe from the form's event when you no longer need them, by adding to the Player a method like this:

public void Dispose(Form form)
{
    form.KeyDown -= ReadKeyDown;
}

...and calling Dispose whenever you dispose a player object.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • That's good to know about the garbage collector, Players live pretty long, but not as long as the form they are on. The main issue with the KeyDown however is that KeyDown on the player class was not recognized (check @Aybe's answer for more detail). but, thanks for the heads up about the GC. – Sander Koldenhof Apr 12 '19 at 22:52