DataGrid上的KeyUp事件未触发

3

我不知道为什么它不起作用,这里是示例代码:

public Form1()
        {
            InitializeComponent();
            //Create DataGrid
            DataGrid dg = new DataGrid();
            dg.Parent = this;
            dg.Location = new Point(10, 10);
            dg.Size = new System.Drawing.Size(300, 200);
            //Create list of people
            List<Person> people = MethodThatFetchesPeople();
            //Bind list
            BindingList<Person> bl_people = new BindingList<Person>(people);
            dg.DataSource = bl_people;
            //Format grid
            dg.TableStyles.Clear();
            DataGridTableStyle dgts = new DataGridTableStyle();
            dgts.MappingName = bl_people.GetType().Name;
            dgts.ReadOnly = true;
            DataGridTextBoxColumn col_name = new DataGridTextBoxColumn();
            col_name.MappingName = "Name";
            col_name.HeaderText = "Name";
            dgts.GridColumnStyles.Add(col_name);
            DataGridTextBoxColumn col_height = new DataGridTextBoxColumn();
            col_height.MappingName = "Height";
            col_height.HeaderText = "Height (cm)";
            dgts.GridColumnStyles.Add(col_height);
            dg.TableStyles.Add(dgts);
            //Subscribe events
            col_name.TextBox.KeyDown += new KeyEventHandler(TextBox_KeyDown);
            col_name.TextBox.KeyUp += new KeyEventHandler(TextBox_KeyUp);
        }

事件处理方法:
        void TextBox_KeyUp(object sender, KeyEventArgs e)
        {
            //Do something on keyup
            Debug.WriteLine("Keyup!");
        }

        void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            //Do something on keydown
            Debug.WriteLine("Keydown!");
        }
    }

在按下名称列中的某个值后,DataGridTextBoxColumn会获得焦点。然后,每当我按键时,KeyDown事件会被触发,但是KeyUp事件没有任何反应,即使KeyDown事件未被订阅。
我真正需要的只是KeyUp事件,而KeyDown不符合我的目的。而且我不能切换到DataGridView,因为这段代码将与紧凑框架一起使用 :(
我该如何解决这个问题?


这个问题也发生在完整的 .Net Framework 上,我只是将它粘贴到一个新项目中,并尝试使用一个通用的 Person 类:public class Person { public string Name { get; set; } public int Height { get; set; } public int Children { get; set; } } - Tea With Cookies
我猜你需要子类化DataGridTextBoxColumn,这样你就可以提供自己的子类化Textbox类作为宿主控件,以便你可以钩入OnKeyDown。 - tcarvin
看一下这个UI库https://b2kui.codeplex.com/,它实现了一个可编辑的CF数据网格,并有一些类作为处理按键事件的一些类似问题的解决方法。完全透明:我维护这个项目。 - BenCamps
2个回答

2
我曾经在Windows Forms / 桌面应用程序上看到过这种情况,但在这里发布以防它也适用于移动设备。
DataGrid控件有一种“吞噬”某些键盘事件的习惯。 它们在内部处理(我认为是由各个网格单元格处理),并且它们不会“冒泡”到其他控件,因为事件已被消耗。
有两种不同的方法可以做到这一点。 基本上,您需要设置表单以在触及DataGrid之前拦截事件,然后预处理并决定是否还要将事件传递给DataGrid。
要在应用程序中创建“通用过滤器”,请执行以下操作。 如果您正在遵循调度程序模式并且可能需要将按键传输路由到许多不同的控件之一,则应执行此操作:
在您的表单构造函数中:
this.KeyPreview = true;
Application.AddMessageFilter(this);

在您的表单中覆盖此方法。如果这个方法返回“true”,事件将被消耗,并且不会分派到任何其他控件。如果这个方法返回“false”,事件将像平常一样通过所有控件冒泡。
    // This is the ONLY way to prevent buttons, checkboxes, and datagrids from processing the UP and DOWN arrows
    const int WM_KEYDOWN       = 0x100;
    const int WM_KEYUP         = 0x101;
    public bool PreFilterMessage(ref Message m)
    {
        try
        {

            if (m.Msg == WM_KEYDOWN)
                // handle event here and return true
            else if (m.Msg == WM_KEYUP)
                // handle event here and return true
            }
        }
        catch
        {
            return false;
        }

    return false;
    }

大约十年前,我写了/计算出了所有这些内容,所以可能有其他/更好的方法来做到这一点,但这对我起作用,我不必创建任何控件的自定义实现就可以使其工作。
我在 MSDN 文章中发现了另一种技术。它是为 VB 编写的,但是很容易转换成 C#。

https://support2.microsoft.com/default.aspx?scid=kb;en-us;320583&Product=vbNET

这里的基本前提是,对DataGrid进行子类化并覆盖ProcessCmdKey方法。

谢谢回复,将 IMessageFilter 实现在窗体上是一种解决方法,但是你提到的第二种解决方案不起作用,因为 ProccessCmdKey 方法无法捕获 wm_keyup,只能捕获 wm_keydown。 - Tea With Cookies
公平地说,我没有测试第二个解决方案,只是偶然发现并想包含在内以防有用。我认为第二个解决方案的前提是正确的,但您可能需要子类化不同的元素,例如网格列或单元格来捕获KeyUp事件。 - user700390

0

这篇MSDN文章建议CF中的键盘事件处理并不容易,但可能会提供一种解决方案。我没有全部阅读。


谢谢您的回复,但那篇文章似乎是针对那些想探索Windows CE本地特性的人...在这种情况下,我只想让keyup事件触发,但我真的弄不清为什么它不起作用:( - Tea With Cookies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接