C# 在窗体中处理箭头键

C# 在窗体中处理箭头键,c#,winforms,keydown,arrow-keys,C#,Winforms,Keydown,Arrow Keys,我刚刚发现,我们不能将按键向下事件直接用于图片盒。所以我必须改变我的策略 我决定将Keydown事件添加到实际表单中: private void FullColourPaletteForm_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.Left: { MessageBox.Show("Left");

我刚刚发现,我们不能将
按键向下
事件直接用于
图片盒
。所以我必须改变我的策略

我决定将
Keydown
事件添加到实际表单中:

private void FullColourPaletteForm_KeyDown(object sender, KeyEventArgs e)
{
    switch (e.KeyCode)
    {
        case Keys.Left:
            {
                MessageBox.Show("Left");
                e.Handled = true;
                return;
            }
    }

}
不会被处决。当我按下左键时,没有看到消息框。相反,它只是将cusor从一个控制移动到另一个控制

我希望能够通过截取图片框内的箭头键来模拟对颜色块的某种光标支持

我不确定前进的最佳途径。我不想破坏在控件之间移动的标准对话功能,但我现在想包括suipport for detectign key,这样我就可以添加代码来移动我的颜色块

能做到吗?不确定为什么我的事件不会在表单中触发

我看到了这个。因此,我尝试设置我的表单KeyPreview属性。没有快乐。我还查看了
ProcessCmdKey
,但它似乎不适合当前的问题

更新:

如果我尝试按照注释中的想法创建一个SelectablePictureBox控件,它如下所示:

我有两个问题。1.我似乎仍然不知道如何处理pictureBox对象本身上的keydown事件。我不愿意在设计器文件中手动添加任何处理程序,以防更改丢失


此外,当使用光标键对窗体执行常规控件管理时,它似乎不知道此控件。

如果要在窗体级别处理箭头键,可以通过以下方式重写窗体的
ProcessCmdKey
函数:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Left)
    {
        MessageBox.Show("Left");
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}
using System;
using System.Reflection;
using System.Windows.Forms;
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        this.pictureBox1.SetStyle(ControlStyles.Selectable, true);
        this.pictureBox1.SetStyle(ControlStyles.UserMouse, true);
        this.pictureBox1.PreviewKeyDown +=
            new PreviewKeyDownEventHandler(pictureBox1_PreviewKeyDown);
    }
    void pictureBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        if (e.KeyData == Keys.Left)
            MessageBox.Show("Left");
    }
}
public static class Extensions
{
    public static void SetStyle(this Control control, ControlStyles flags, bool value)
    {
        Type type = control.GetType();
        BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
        MethodInfo method = type.GetMethod("SetStyle", bindingFlags);
        if (method != null)
        {
            object[] param = { flags, value };
            method.Invoke(control, param);
        }
    }
}
但一般来说,最好创建一个自定义的paint可选控件,比如,而不是将这种逻辑放在表单级别。您的控件应该包含这样的逻辑


注意

OP:我刚刚发现不能直接使用
KeyDown
事件 带有
图片盒

如中所述,
PictureBox
控件不可选择,默认情况下无法对焦,并且您无法处理控件的键盘事件

但您可以通过以下方式强制其可选择并支持键盘事件:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Left)
    {
        MessageBox.Show("Left");
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}
using System;
using System.Reflection;
using System.Windows.Forms;
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        this.pictureBox1.SetStyle(ControlStyles.Selectable, true);
        this.pictureBox1.SetStyle(ControlStyles.UserMouse, true);
        this.pictureBox1.PreviewKeyDown +=
            new PreviewKeyDownEventHandler(pictureBox1_PreviewKeyDown);
    }
    void pictureBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        if (e.KeyData == Keys.Left)
            MessageBox.Show("Left");
    }
}
public static class Extensions
{
    public static void SetStyle(this Control control, ControlStyles flags, bool value)
    {
        Type type = control.GetType();
        BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
        MethodInfo method = type.GetMethod("SetStyle", bindingFlags);
        if (method != null)
        {
            object[] param = { flags, value };
            method.Invoke(control, param);
        }
    }
}

至少知道这种方法是一种黑客行为,您可以在将来重用扩展方法来启用或禁用控件上的某些样式。

它不起作用,因为PictureBox不是一个可以获得焦点的控件。你唯一能得到它的控件是按钮。你应该把它修好,这并不难。检查进近。您的“确定”和“取消”按钮向后。它们不遵循标准的Windows约定。(是的,OSX的做法有所不同。是的,这可能是一个更好的约定。但它不是您的用户习惯的约定,因此它不是您应该遵循的约定。)设计器在属性窗口中隐藏事件。您也可以使用[Browsable]属性轻松地解决这个问题,但实际上并不需要,只需在表单构造函数中订阅它即可。按钮顺序如下,从左到右:帮助(可选)/确定,或启动整个窗口操作的任何命令按钮/取消/应用(可选)。如果命令按钮仅适用于特定控件,则将其与该控件分组;不要将其放在按钮行中。按以下顺序显示提交按钮:确定/[执行]/是,[不执行]/否,取消,应用(如果存在),帮助(如果存在)谢谢。这确实有效,尽管我失去了一般控制运动的支持。我把它改为Control+Arrow,没关系。谢谢你的回答。在C#中似乎有很多方法可以做事情。目前,根据Hans的评论,我已经使用继承的类完成了这项工作。我认为你的方法更容易实现。一种方法比另一种方法有好处吗?正如答案中提到的,如果您想创建一个可重用的控件,最好在控件中封装这样的逻辑。但是如果你不希望它是可重用的,你可以简单地应用我共享的两种方法。至少知道第二种方法是一种黑客,你可以重用扩展方法来启用或禁用控件上的某些样式;我第一次读到你的答案时,遗漏了斜体部分。我并不是想暗示你的回答没有用,只是想表明我强烈希望……嗯,完全按照你说的做“总体上……更好”。——)我确实看到一些人不愿意“不引入新的控制”,但我不理解这一点。这似乎要么是一种非理性的恐惧,要么是源于对对象模型的根本误解。您可以使用子类来修改和扩展行为。可重用性只是一个额外的好处。