如何在DataGridView编辑模式下使工作标准快捷键(Ctrl+C,Ctrl+Z)生效?

4
我有一个简单的.NET应用程序,其中包含每个选项卡上的datargridviews。我已经将主菜单添加到窗体中,并使用标准属性为菜单项分配了快捷键。
editMenuItem = new ToolStripMenuItem("Copy", null, new System.EventHandler(onCopyCut_Click));
editMenuItem.ShortcutKeys = Keys.Control | Keys.C;

上面显示的菜单项只是将单元格内容复制到剪贴板。这很好用,但在DGV的编辑模式下,Ctrl+C和其他标准热键不再起作用!我已将Form.KeyPreview属性设置为true,并尝试关闭我的Form对象的Handled属性,但仍然没有任何反应:
    void FileOrginizerForm_KeyDown(object sender, KeyEventArgs e)
    {
            ...
        if (gridView.CurrentCell.IsInEditMode)
            e.Handled = false;
    }

我错过了什么?我确定这应该是一些简单的东西。
我在 msdn帮助页面的评论上找到了一些信息:
需要注意的一件事是,如果表单中有文本框控件,则菜单项的ShortcutKeys将拦截该组合键,文本框将永远无法接收它,例如,如果您有一个粘贴(ctrl + v)ShortcutKey,则您的文本框永远不会接收粘贴命令。据微软称,这是设计如此。他们的解决方法是暂时清除菜单项的ShortCutKey属性以允许黏贴命令(很可能是在事件期间),然后在事件完成后重新设置它。 解决方法: 我最终通过从主表单的KeyDown事件处理程序调用菜单事件处理程序来解决问题,而不是打开和关闭菜单快捷方式。
    void FileOrginizerForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (!gridView.CurrentCell.IsInEditMode)
        {
            if (e.KeyData == (Keys.Control | Keys.Z))
            {
                this.editToolStripMenuItem.DropDownItems["Undo"].PerformClick();
            }
            else if (e.KeyData == (Keys.Control | Keys.Y))
            {
                this.editToolStripMenuItem.DropDownItems["Redo"].PerformClick();
            }
            else if (e.KeyData == (Keys.Control | Keys.X))
            {
                    this.editToolStripMenuItem.DropDownItems["Cut"].PerformClick();
            }
            else if (e.KeyData == (Keys.Control | Keys.C))
            {
                    this.editToolStripMenuItem.DropDownItems["Copy"].PerformClick();
            }
            else if (e.KeyData == (Keys.Control | Keys.V))
            {
                    this.editToolStripMenuItem.DropDownItems["Paste"].PerformClick();
            }
            else if (e.KeyData == (Keys.Control | Keys.A))
            {

this.selectToolStripMenuItem.DropDownItems["Select All"].PerformClick();
            }
        }
    }

当 DGV 进入 DataGridViewTextBoxColumn(默认列类型) 单元格的编辑模式时,它会创建一个 TextBox 控件并将其移动到单元格的区域。 此控件 (DataGridView.EditingControl) 是具有焦点的控件。与表单上的任何其他 TextBox 一样,此 TextBox 的相同快捷键规则适用。 - Tergiver
是的,但问题在于 ToolStripMenuItem.ShortcutKeys 属性会覆盖 TextBox 的标准快捷键。 - sergo
3个回答

2
您可以使用下面演示中显示的两个事件来暂时删除菜单项中的快捷方式。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

public class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1()
    {
        var dgv = new DataGridView
        {
            Dock = DockStyle.Fill,
            DataSource = new List<DummyObject>
            {
                new DummyObject { Name = "One", Value = 1 },
                new DummyObject { Name = "Two", Value = 2 },
                new DummyObject { Name = "Three", Value = 3 },
            }
        };
        dgv.EditingControlShowing += (s, e) => e.Control.VisibleChanged += DgvEditingControlVisibleChanged;
        Controls.Add(dgv);
    }

    void DgvEditingControlVisibleChanged(object sender, EventArgs e)
    {
        Control control = sender as Control;
        if (control.Visible)
        {
            // The editing control has become visible.

            Trace.WriteLine(String.Format("Editing control showing {0}", control));
        }
        else
        {
            // The editing control has been removed.

            // Remove the event handler because the DGV can use multiple
            //  editing controls if it has different column types. 
            control.VisibleChanged -= DgvEditingControlVisibleChanged;
            Trace.WriteLine(String.Format("Editing control removed {0}", control));
        }
    }
}

public class DummyObject
{
    public string Name { get; set; }
    public int Value { get; set; }
}

谢谢你的这个神奇代码 - dgv.EditingControlShowing += (s, e) => e.Control.VisibleChanged += DgvEditingControlVisibleChanged; 但还是有很多麻烦。对我来说,KeyDown事件似乎更容易些。 - sergo
简单的方法是在“直接API应用程序”(即无框架)中完成。通常,剪切/复制/粘贴菜单项将简单地向具有焦点的控件发送WM_COMMAND(ID_CUT、ID_COPY、ID_PASTE)。看起来Windows Forms的管道使这比它应该更困难。您可以简单地按照直接API应用程序的方式执行,并p/invoke SendMessage(this.ActiveControl.Handle, WM_COMMAND, ID_COPY, 0)。我不太熟悉WinForms管道,不知道是否有更好的方法。 - Tergiver

1
如果您将SendKeys.Send("^c");添加到菜单项的单击事件中,则无需从菜单项中删除快捷方式。

0

只需从菜单项中删除快捷方式,并将其文本放入菜单项文本中。这适用于在表单上使用快捷方式,但如果单击菜单项本身,则仍需要编码。


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