Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 取消控件上的某些键盘事件_C#_.net_Datagridview_Event Handling - Fatal编程技术网

C# 取消控件上的某些键盘事件

C# 取消控件上的某些键盘事件,c#,.net,datagridview,event-handling,C#,.net,Datagridview,Event Handling,我有一个带有KeyDown和KeyUp处理程序的DataGridView。在某些情况下,我想禁用Enter键的默认行为(取消选择文本并聚焦于下一行),非常类似于这样: private void View_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter && Condition) { // Special flow - d

我有一个带有KeyDown和KeyUp处理程序的DataGridView。在某些情况下,我想禁用Enter键的默认行为(取消选择文本并聚焦于下一行),非常类似于这样:

    private void View_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter && Condition)
        {
            // Special flow - do logic and CANCEL default event effect
            SpecialFlow = true;
            ...
            e.Handled = true; // That doesn't do the job
        }
    }

    private void View_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter && Condition && SpecialFlow)
        {
            // Special flow - do logic and continue normally
            SpecialFlow = false;
            ...
        }
    }

我找到了一些似乎不符合我需要的解决方案:

  • 用钩子截取应用程序中的所有键盘事件-我需要更多的检查才能做到这一点
  • 删除所有事件处理程序-但我需要在密钥启动后将它们返回
  • 实施一项新的控制措施-溢流
简单地说,是否有一种方法可以在处理程序之后(就在默认处理之前)截获键事件,并且仅在特殊流中截获

已解决:

我遇到的问题是根本没有调用KeyDown,因为单元格处于编辑模式,基本上没有办法阻止默认的行为,即按Enter键结束编辑模式。因此,我添加了一个标记,用于在编辑模式结束后在编辑模式下返回所选文本-在KeyUp处理程序中

大致如下:

    private void View_CellEndEdit(object sender, DataGridViewCellEventArgs e)
    {
        if (Condition)
            EndEditFlag = true;
    }

    private void View_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter && Condition)
        {
            if (EndEditFlag)
            {
                EndEditFlag = false;
                // Select by previously saved selection data - revert CellEndEdit
                View.CurrentCell = View.Rows[...].Cells[...];
                SelectText(...);
            }
            // Special flow - do logic
        }
    }

我不确定我是否正确理解了你的问题。但是如果我没有错的话,您所需要的只是KeyEventArgs对象上的“Handled”属性

在事件处理程序中将该属性设置为“true”时,不会调用该特定事件的进一步处理:

    public void Test()
    {
        DataGridView view = new DataGridView();

        view.KeyDown += view_KeyDown;
    }

    void view_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter /* && some other conditions */)
        {
            //Do some custom logic
            e.Handled = true; //Cencel event. Avoid any other processing. Like the button was never pressed.
        }
    }

我不确定我是否正确理解了你的问题。但是如果我没有错的话,您所需要的只是KeyEventArgs对象上的“Handled”属性

在事件处理程序中将该属性设置为“true”时,不会调用该特定事件的进一步处理:

    public void Test()
    {
        DataGridView view = new DataGridView();

        view.KeyDown += view_KeyDown;
    }

    void view_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter /* && some other conditions */)
        {
            //Do some custom logic
            e.Handled = true; //Cencel event. Avoid any other processing. Like the button was never pressed.
        }
    }

对此的深入解决方案可能会变得相当复杂。我建议首先尝试一下
KeyEventArgs
SuppressKeyPress
属性。如果在
视图中将其设置为true\u KeyDown
,则可能不会触发标准行为。如果是这样,就离开这里

否则,您将不得不在按键时搞乱windows消息的处理方式。我正是在做这个,在一个我正在做的项目中

我的方法简介: 将有问题的控件放入从
UserControl
下降的容器中。这允许通过一些自定义代码覆盖
ProcessKeyPreview
方法,在这些自定义代码中,前面提到的与windows消息的混淆已经完成。实际上,user32.dll中的PeekMessage用于在不需要的windows消息被重写
ProcessKeyPreview
处理后,将其从消息队列中取出

让我们深入了解容器的代码:

public class baseKeyControl : UserControl
{
    private const int WM_KEYDOWN = 0x100;
    private const int WM_KEYUP = 0x101;
    const int WM_CHAR = 0x102;
    const int WM_SYSCHAR = 0x106;
    const int WM_SYSKEYDOWN = 0x104;
    const int WM_SYSKEYUP = 0x105;
    const int WM_IME_CHAR = 0x286;

    private struct MSG
    {
        public IntPtr hwnd;
        public int message;
        public IntPtr wParam;
        public IntPtr lParam;
        public int time;
        public int pt_x;
        public int pt_y;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern bool PeekMessage([In, Out] ref MSG msg,
                                               HandleRef hwnd, int msgMin, int msgMax, int remove);        

    /// <summary>
    /// Trap any keypress before child controls get hold of them
    /// </summary>
    /// <param name="m">Windows message</param>
    /// <returns>True if the keypress is handled</returns>
    protected override bool ProcessKeyPreview(ref Message m)
    {
        KeyEventArgs e = null;

        if ((m.Msg != WM_CHAR) && (m.Msg != WM_SYSCHAR) && (m.Msg != WM_IME_CHAR))
        {
            e = new KeyEventArgs(((Keys)((int)((long)m.WParam))) | ModifierKeys);
            if ((m.Msg == WM_KEYDOWN) || (m.Msg == WM_SYSKEYDOWN))
            {
                this.DoTrappedKeyDown(e);
            }
            else if ((m.Msg == WM_KEYUP) || (m.Msg == WM_SYSKEYUP))
            {
                this.DoTrappedKeyUp(e);
            }

            // Remove any WM_CHAR type messages if supresskeypress is true.
            if (e.SuppressKeyPress)
            {
                this.RemovePendingMessages(WM_CHAR, WM_CHAR);
                this.RemovePendingMessages(WM_SYSCHAR, WM_SYSCHAR);
                this.RemovePendingMessages(WM_IME_CHAR, WM_IME_CHAR);
            }

            if (e.Handled)
            {
                return e.SuppressKeyPress;
            }
        }

        return base.ProcessKeyPreview(ref m);
    }

    private void RemovePendingMessages(int msgMin, int msgMax)
    {
        if (!this.IsDisposed)
        {
            MSG msg = new MSG();
            IntPtr handle = this.Handle;

            while (PeekMessage(ref msg,
                               new HandleRef(this, handle), msgMin, msgMax, 1))
            {
            }
        }
    }

    public void DoTrappedKeyDown(KeyEventArgs e)
    {
        // Do your key down work here
    }

    public void DoTrappedKeyUp(KeyEventArgs e)
    {
        // Do your key up work here
    }
}
公共类baseKeyControl:UserControl
{
私有常量int WM_KEYDOWN=0x100;
私有常量int WM_KEYUP=0x101;
常量int WM_CHAR=0x102;
常量int WM_SYSCHAR=0x106;
常量int WM_SYSKEYDOWN=0x104;
常量int WM_SYSKEYUP=0x105;
常量int WM_IME_CHAR=0x286;
私有结构消息
{
公共IntPtr hwnd;
公共信息;
公共IntPtr wParam;
公共IntPtr LPRAM;
公共整数时间;
公共int pt_x;
公共国际部;
}
[DllImport(“user32.dll”,CharSet=CharSet.Auto)]
私有静态外部bool peek消息([In,Out]ref MSG,
HandleRef hwnd、int msgMin、int msgMax、int remove);
/// 
///在子控件抓住任何按键之前,将其捕获
/// 
///Windows消息
///如果已处理按键,则为True
受保护的覆盖布尔ProcessKeyPreview(参考消息m)
{
KeyEventArgs e=null;
if((m.Msg!=WM\u CHAR)&&&(m.Msg!=WM\u SYSCHAR)&&&(m.Msg!=WM\u IME\u CHAR))
{
e=新的KeyEventArgs(((键)((int)((长)m.WParam)))| ModifierKeys);
if((m.Msg==WM_KEYDOWN)| |(m.Msg==WM_SYSKEYDOWN))
{
这个。DoTrappedKeyDown(e);
}
else if((m.Msg==WM_-KEYUP)| |(m.Msg==WM_-SYSKEYUP))
{
这是DoTrappedKeyUp(e);
}
//如果SupersKeyPress为true,则删除任何WM_字符类型的消息。
如果(如按下按键)
{
这个.removependengmessages(WM_CHAR,WM_CHAR);
这个.removependengmessages(WM_SYSCHAR,WM_SYSCHAR);
这个.removependengmessages(WM_IME_CHAR,WM_IME_CHAR);
}
如果(如已处理)
{
返回e.suppress按键;
}
}
返回base.ProcessKeyPreview(参考m);
}
私有void RemovePendingMessages(int-msgMin,int-msgMax)
{
如果(!this.IsDisposed)
{
MSG=new MSG();
IntPtr handle=this.handle;
while(peek)消息(参考消息,
新的HandleRef(这个,handle),msgMin,msgMax,1))
{
}
}
}
public void DoTrappedKeyDown(KeyEventArgs e)
{
//你的钥匙在这里工作吗
}
public void DoTrappedKeyUp(KeyEventArgs e)
{
//你的钥匙在这里工作吗
}
}

请注意错误,因为我已经从我现有的代码中快速复制并粘贴了这段代码,这段代码做的更多,是根据我的特定用例定制的。出于可读性原因,不希望在此处显示此内容。

对此的深入解决方案可能会变得相当复杂。我建议首先尝试一下
KeyEventArgs
SuppressKeyPress
属性。如果在
视图中将其设置为true\u KeyDown
,则可能不会触发标准行为。如果是这样,就离开这里

否则,您将不得不在按键时搞乱windows消息的处理方式。我正是在做这个,在一个我正在做的项目中

我的方法简介: 将有问题的控件放入从
UserControl
下降的容器中。这允许覆盖
ProcessKeyPre