【问题标题】:mouse right-click contextMenuStrip doesn't show ONLY for the first time鼠标右键单击 contextMenuStrip 仅第一次不显示
【发布时间】:2026-02-13 23:25:06
【问题描述】:

我得到了这部分代码,我打开 contextMenuStrip 以响应鼠标右键单击(在 dataGridView 表上)。

问题是,我第一次右键单击 - 菜单没有弹出。第二次弹出,从那以后一切正常..

    private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
    {
        DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y); //get info
        int currentMouseOverRow = dataGridView1.HitTest(e.X, e.Y).RowIndex;

        if (e.Button == MouseButtons.Right) //MouseButton right: Open context menu strip.
         {
             dataGridView1.Rows[currentMouseOverRow].Selected = true; //Select the row

             ContextMenuStrip Menu = new ContextMenuStrip();
             ToolStripMenuItem MenuOpenPO = new ToolStripMenuItem("Delete it");
             MenuOpenPO.Click += new EventHandler(MenuOpenPO_Click);
             Menu.Items.AddRange(new ToolStripItem[] { MenuOpenPO });
             dataGridView1.ContextMenuStrip = Menu; //Assign to dataGridView1
         }
    }

有什么帮助吗? :) 我使用 Visual Studio 2012。

【问题讨论】:

    标签: c# datagridview mouseevent contextmenustrip


    【解决方案1】:

    问题:您已在RightClick 事件之后将ContextMenu 添加到DataGridView。所以ContextMenu 将在第一个RightClick 之后添加到您的DataGridView,因此用户可以从进一步的RightClick 事件中看到附加的ContextMenu

    解决方案:您需要在右键单击DataGridView 之前添加ContextMenu,这样每个RightClick 事件都会显示它。

    注意:如果ContextMenu被分配给任何控件,它会默认显示在rightclick上,意味着你不需要为控件上的每个RightClick事件显式添加它.

    试试这个:在Form Load 事件中

       private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            ContextMenuStrip Menu = new ContextMenuStrip();
            ToolStripMenuItem MenuOpenPO = new ToolStripMenuItem("Delete it");
            MenuOpenPO.Click += new EventHandler(MenuOpenPO_Click);
            Menu.Items.AddRange(new ToolStripItem[] { MenuOpenPO });
            dataGridView1.ContextMenuStrip = Menu; //Assign to dataGridView1
        }
    

    【讨论】:

    • 哦,哇。这解释了很多。谢谢你。通过禁用它所绑定的控件,菜单很容易被禁用。
    【解决方案2】:

    我通常创建我自己的ContextMenuStrip 对象(私有变量)并在需要时创建Show()。我怀疑它是第一次分配,但无法显示,因为新添加的菜单没有自己的右键单击触发器显示。这只会发生第二次,一旦它存在。

    像这样: 私有 ContextMenuStrip _myMenu;

    private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
    {
        DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y); //get info
        int currentMouseOverRow = dataGridView1.HitTest(e.X, e.Y).RowIndex;
    
        if (e.Button == MouseButtons.Right) //MouseButton right: Open context menu strip.
         {
             dataGridView1.Rows[currentMouseOverRow].Selected = true; //Select the row
    
             _myMenu = new ContextMenuStrip();
             ToolStripMenuItem MenuOpenPO = new ToolStripMenuItem("Delete it");
             MenuOpenPO.Click += new EventHandler(MenuOpenPO_Click);
             _myMenu.Items.AddRange(new ToolStripItem[] { MenuOpenPO });
             _myMenu.Show(new Point(e.X, e.Y));
         }
    }
    

    【讨论】:

    • +1 您应该在不再需要旧菜单时将其丢弃,否则我想您会泄漏资源
    • @SriramSakthivel 泄漏什么?它是一个本地对象,其范围为父对象(我认为是Form)。它每次都被初始化的事实并不表示有多个实例。
    • 你会泄露一个UserObject,我的意思是一个控件,在这种情况下是ContextMenuStrip。如果未引用,控件将不会被垃圾回收,ContextMenuStrip 也是一个控件。你正在创建 _myMenu = new ContextMenuStrip(); 新实例,你在哪里处理它?
    • 通常不需要显式处理;一旦不再显示,旧对象将被取消引用,并将被垃圾收集器清理。