c# how do I get the rowindex from a contextmenu?

I have a context menu with an event handler for the menu item.  I can get into it, but I can't get the rowindex that was clicked on.

        public static void DataGridViewContextMenuOptionChain(this DataGridView dataGrid)
        {
            ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
            ToolStripMenuItem toolStripToggleActive = new ToolStripMenuItem("Toggle Active");
            ToolStripMenuItem toolStripDeleteChain = new ToolStripMenuItem("Delete Chain");

            toolStripToggleActive.Click += toolStripToggleActive_Click;
            toolStripDeleteChain.Click +=toolStripDeleteChain_Click;
            contextMenuStrip.Items.AddRange(new ToolStripItem[] { toolStripToggleActive, toolStripDeleteChain});
            dataGrid.ContextMenuStrip = contextMenuStrip;
        }

        private static void toolStripDeleteChain_Click(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }
jackjohnson44Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jackjohnson44Author Commented:
One more thing to mention is that I am adding the above as an extension method in a static class to reuse it.  I am not adding this to a form, so I can't just make a reference to a hard coded grid in the event handlers.
0
Jacques Bourgeois (James Burger)PresidentCommented:
I do it by handling myself the display of the ContextMenu instead of leaving the system do it. That means first that you do not associate the menu with the dataGrid. This comes from a VB application, but can be easily translated to C#. I also had to cleanup the thing because there was a lot of extra code around this basic demonstration, I hope that I did not break it while doing so.

The technique is there anyway. Up to you to adjust it to your needs. If you go for a static method however, do not instantiate the menu from inside the method. It will create a new menu each time that a grid will try to attach itself to the mechanism. If you are not careful, you might even end up with many menus for a given grid. Create a static menu in the class instead, so that all the grids will share the same menu, thus saving on resources.

In the MouseClick event of the grid, I detect a right mouse click, row and cell where the click occurred, and then call a method that will display the menu:
Private Sub DataGridViewExt_MouseClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles DataGridViewExt.MouseClick

     If e.Button = Windows.Forms.MouseButtons.Right Then
          Dim hitTestInfo As DataGridView.HitTestInfo
          hitTestInfo = Me.HitTest(e.Location.X, e.Location.Y)
          If hitTestInfo.RowIndex = -1 Then 'Click is not in a cell
               Exit Sub 
          End If
          TriggerMenu(DataGridViewExt.Item(hitTestInfo.ColumnIndex, hitTestInfo.RowIndex, e.Location)) 'The method that receives that call will have what it needs to display the menu at the correct position:
     End If

End Sub

Open in new window

Then, assuming that the ContextMenu is ready, simply make it visible at the correct location:
Public Sub TriggerMenu(cell As DataGridViewCell)
     _menu.Show(cell.DataGridView, e.Location)
End Sub

Open in new window


For your purpose, all you have to do after the Show is to retrieve cell.RowIndex and do your stuff.

In my case, I call the mechanism from the Form that contains the grid. But since in your case you handle the event inside of your own class, you could simply put everything in a toolStripDeleteChain_MouseClick event instead of the Click event you wanted to implement. Click has the big disadvantage of not giving you the parameters required.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jackjohnson44Author Commented:
Thanks!


I ended up creating a class for the context menu item which contains the creating as well as events for the context menu.  I use a variation of your code to grab the row index.

I just create an instance of the object on my main form and pass in the datagrid.  The best part is that I can associate it with any grid that has the same column ID.  I have several similar grids on other pages.

How I call it:
                var contextMenuController = new ContextMenuDataGridSpread(dataGrid, _currentChain);

The class:

    public class ContextMenuDataGridSpread
    {
        private DataGridView _dataGridView;
        private int _rowIndex = -1;
        private OrderChain _orderChain;

        public ContextMenuDataGridSpread(DataGridView dataGrid, OrderChain orderChain)
        {
            _dataGridView = dataGrid;
            _orderChain = orderChain;
            CreateContextMenu(dataGrid);
        }

        private void CreateContextMenu(DataGridView dataGrid)
        {
            ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
            ToolStripMenuItem toolStripEdit = new ToolStripMenuItem("Edit Spread");
            toolStripEdit.Click += toolStripEdit_Click;
            contextMenuStrip.Items.AddRange(new ToolStripItem[] { toolStripEdit});
            dataGrid.ContextMenuStrip = contextMenuStrip;
            dataGrid.MouseDown += dataGrid_MouseDown;
        }

        void toolStripEdit_Click(object sender, EventArgs e)
        {
            var spreadId = _dataGridView.GetStringValFromSelRow("ID");
            var currentSpread = _orderChain.GetSpreadBySpreadId(spreadId);

            using (var form = new FormInputComplex(currentSpread))
            {
                var result = form.ShowDialog();
                if (result == DialogResult.OK)
                {
                    _orderChain.Save();
                }
            }
        }

        public void dataGrid_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                DataGridView.HitTestInfo hit = _dataGridView.HitTest(e.X, e.Y);
                if (hit.Type == DataGridViewHitTestType.Cell)
                {
                    _rowIndex = hit.RowIndex;
                }
                else
                {
                    _rowIndex = -1;
                }
            }
        }


    }
0
jackjohnson44Author Commented:
I've requested that this question be closed as follows:

Accepted answer: 0 points for jackjohnson44's comment #a39473938
Assisted answer: 500 points for JamesBurger's comment #a39472539

for the following reason:

Thanks!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.