【问题标题】:Why does my WinForms context menu not appear where the mouse is?为什么我的 WinForms 上下文菜单没有出现在鼠标所在的位置?
【发布时间】:2011-02-23 16:39:05
【问题描述】:

在我的应用程序中,我有一个DataGridView,用于配置一些选项。这个想法是您可以在第一列中输入您想要的任何文本,但是如果您右键单击它将为您提供明确支持的值。我需要这是一个文本框而不是下拉列表,因为我需要支持编辑无效(或旧)配置。

我想要的是用户在字段名称列中单击鼠标右键,并拥有一个上下文菜单,该菜单根据这是什么类型的配置而有效。因此,我编写了以下事件

    private void grvFieldData_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
        // If this is a right click on the Field name column, create a context menu 
        //   with recognized options for that field
        if (e.Button == MouseButtons.Right && grvFieldData.Columns[e.ColumnIndex].Name == "clmFieldName")
        {
            ContextMenu menu = new ContextMenu();

            if (_supportedDataGrids.ContainsKey((cmbDataGrid.SelectedItem as DataGridFieldList).GridName))
            {
                // Loop through all the fields and add them to the context menu
                List<string> fields = _supportedDataGrids[((cmbDataGrid.SelectedItem as DataGridFieldList).GridName)];
                fields.Sort();

                foreach (string field in fields)
                    menu.MenuItems.Add(new MenuItem(field));

                // Make sure there is at least one field before displaying the context menu
                if (menu.MenuItems.Count > 0)
                    menu.Show(this, e.Location, LeftRightAlignment.Right);
            }
        }
    }

这“正确”工作,但上下文菜单出现在表单的顶部,而不是鼠标指针所在的位置。如果我将 Show() 调用更改为使用 DataGridView 而不是表单,我会遇到同样的问题,但它会出现在网格的左上角,而不是鼠标所在的位置。

奇怪的是,如果我将此事件更改为 MouseClick 事件(而不是 CellMouseclick 事件),一切正常,并且上下文菜单准确出现在鼠标指针所在的位置。这个选项的问题是用户可能没有右键单击当前选择的单元格,这意味着当他们单击菜单项时,所选单元格将被更改,而不是他们右键单击的单元格。

有人知道为什么使用CellMouseClick 创建的上下文菜单没有显示在正确的位置吗?

【问题讨论】:

    标签: c# winforms contextmenu


    【解决方案1】:
     menu.Show(this, e.Location, LeftRightAlignment.Right);
    

    第二个参数是鼠标位置,相对于单元格的左上角。按照编程,您使该偏移量相对于表单 this,这将使菜单出现在表单的左上角。使用 DGV 作为第一个参数也不起作用,现在它位于网格的左上角。

    有几种方法可以解决这个问题,但这是最简单的方法:

     Point pos = this.PointToClient(Cursor.Position);
     menu.Show(this, pos, LeftRightAlignment.Right);
    

    你可以任意替换this为grvFieldData。

    【讨论】:

    • 嘿,我的答案会稍微复杂一点,加上一堆 X 和 Y 坐标。我希望我几周前知道 Cursor.Position! +1 为简单起见!
    • 太棒了,这就像一个魅力! Cursor.Position 是我错过的!
    【解决方案2】:

    在datagridview鼠标点击事件中:

    if e.button= mousebutton.right 
    {
       contextmenu1.Show(MousePosition);
    }
    

    【讨论】:

      【解决方案3】:

      尝试使用PointToClient 获得合适的位置

      【讨论】:

      • 不。 PointToClient(e.Location) 将上下文菜单置于屏幕顶部,PointToScreen(e.Location) 出于某种原因将上下文菜单置于窗体中间。
      • grvFieldData.PointToClient(e.Location)
      • 同样的问题,即使我将this 调用更改为grvFieldData :-/
      【解决方案4】:

      它没有显示在正确的位置,因为 e.Location 是相对于父对象左上角的位置,在这种情况下是单元格本身。位置属性始终与其容器相关。

      要获取鼠标光标相对于表单左上角的位置,可以使用

      this.PointToClient(Cursor.Position);
      

      【讨论】:

      • 如何获取被点击单元格的位置(单元格不是控件,因此我无法将其传递给Show())或鼠标的屏幕位置?
      【解决方案5】:

      我已经解决了这个问题......人们可能会觉得这个方法很奇怪,但它工作正常!) 如果我们想在 datagridview 单元格中按下鼠标右键时看到上下文菜单,并且就在那里,而不是在屏幕中间或其他地方,我们需要:

      制作一些变量

      int x=0;
      int y=0;
      

      为 datagridview1 创建一个“MouseMove”事件,例如:

      private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
      {
         x = e.X;
         y = e.Y;
      }
      

      private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
      {
         if (e.Button == System.Windows.Forms.MouseButtons.Right)
         {
            contextMenuStrip1.Show(dataGridView1, x,y);
         }
      }
      

      欢迎您

      【讨论】:

      • 这个解决方案有不必要的开销,因为用户将鼠标移到网格上(我认为这种情况经常发生)它会不断地写入内存。该事件已包含该位置。
      猜你喜欢
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-16
      • 2013-06-07
      • 1970-01-01
      相关资源
      最近更新 更多