KeyUp 事件未在 DataGrid 上触发
KeyUp event not firing on DataGrid
不明白为什么不是,这里是示例代码:
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!");
}
}
按下 Name 列中的值后,DataGridTextBoxColumn 获得焦点。
然后,每当我按下一个键时, KeyDown 事件就会被触发,但 KeyUp 事件什么也没有发生,即使 KeyDown 事件未订阅。
我真的只需要 KeyUp 事件,KeyDown 不符合我的目的。而且我不能只切换到 DataGridView 因为此代码将与紧凑框架一起使用:(
我该如何解决?
这 MSDN Article 表明 CF 中的键盘事件处理并不容易,但它可能会提供一个解决方案。我没看完。
我看到这种情况特别发生在 Windows 表单/桌面应用程序上,但在这里发帖以防它在移动设备上也适用。
DataGrid 控件有 "swallowing" 某些键盘事件的习惯。它在内部处理它们(我相信它们是由各个网格单元处理的)并且它们不会 "bubble up" 到其他控件,因为事件已经被消耗。
有两种不同的方法可以做到这一点。基本上,您需要设置表单以在事件到达 DataGrid 之前拦截事件,然后进行预处理并决定是否还要将事件传递给 DataGrid。
要在您的应用程序中创建 "Universal Filter",请执行以下操作。如果您遵循调度程序模式并且可能需要将击键路由到许多不同控件之一,则可以这样做:
在您的表单构造函数中:
this.KeyPreview = true;
Application.AddMessageFilter(this);
在您的表单中覆盖此方法。如果此方法 returns "true" 事件将被消耗并且不会被分派给任何其他控件。如果此方法 returns "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;
}
大约 10 年前我写了/想出了所有这些,所以也许还有其他/更好的方法来做到这一点,但这对我有用,我不必创建任何控件的自定义实现来使其工作.
我在 MSDN 文章中找到的另一种技术。它是为 VB 编写的,但应该很容易转换为 C#:
https://support2.microsoft.com/default.aspx?scid=kb;en-us;320583&Product=vbNET
这里的基本前提是继承 DataGrid 并覆盖 ProcessCmdKey
方法。
不明白为什么不是,这里是示例代码:
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!");
}
}
按下 Name 列中的值后,DataGridTextBoxColumn 获得焦点。
然后,每当我按下一个键时, KeyDown 事件就会被触发,但 KeyUp 事件什么也没有发生,即使 KeyDown 事件未订阅。
我真的只需要 KeyUp 事件,KeyDown 不符合我的目的。而且我不能只切换到 DataGridView 因为此代码将与紧凑框架一起使用:(
我该如何解决?
这 MSDN Article 表明 CF 中的键盘事件处理并不容易,但它可能会提供一个解决方案。我没看完。
我看到这种情况特别发生在 Windows 表单/桌面应用程序上,但在这里发帖以防它在移动设备上也适用。
DataGrid 控件有 "swallowing" 某些键盘事件的习惯。它在内部处理它们(我相信它们是由各个网格单元处理的)并且它们不会 "bubble up" 到其他控件,因为事件已经被消耗。
有两种不同的方法可以做到这一点。基本上,您需要设置表单以在事件到达 DataGrid 之前拦截事件,然后进行预处理并决定是否还要将事件传递给 DataGrid。
要在您的应用程序中创建 "Universal Filter",请执行以下操作。如果您遵循调度程序模式并且可能需要将击键路由到许多不同控件之一,则可以这样做:
在您的表单构造函数中:
this.KeyPreview = true;
Application.AddMessageFilter(this);
在您的表单中覆盖此方法。如果此方法 returns "true" 事件将被消耗并且不会被分派给任何其他控件。如果此方法 returns "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;
}
大约 10 年前我写了/想出了所有这些,所以也许还有其他/更好的方法来做到这一点,但这对我有用,我不必创建任何控件的自定义实现来使其工作.
我在 MSDN 文章中找到的另一种技术。它是为 VB 编写的,但应该很容易转换为 C#:
https://support2.microsoft.com/default.aspx?scid=kb;en-us;320583&Product=vbNET
这里的基本前提是继承 DataGrid 并覆盖 ProcessCmdKey
方法。