Create Right Click Menu on dataGridView for entire row
I found a pretty easy way to do what I wanted to do. It goes like this:
first of all, hook up a mouseDown event:
dataGridView1.MouseDown += new MouseEventHandler(this.dataGridView1_MouseClick);
then, create the routine co-responding to the mouseDown event..
private void dataGridView1_MouseClick(Object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ContextMenu cm = new ContextMenu();
this.ContextMenu = cm;
cm.MenuItems.Add(new MenuItem("&Cut", new System.EventHandler(this.cut_Click)));
cm.MenuItems.Add(new MenuItem("&Copy", new System.EventHandler(this.copy2_Click)));
cm.MenuItems.Add(new MenuItem("&Paste", new System.EventHandler(this.paste2_Click)));
cm.Show(this, new Point(e.X, e.Y));
}
}
Then add your event routines, such as:
private void cut_Click(Object sender, EventArgs e)
{
if (this.dataGridView1.GetCellCount(DataGridViewElementStates.Selected) > 0)
{
try
{
Clipboard.SetDataObject(this.dataGridView1.GetClipboardContent());
}
catch (System.Runtime.InteropServices.ExternalException)
{
MessageBox.Show("Clipboard could not be accessed. Please try again.");
}
}
if (this.dataGridView1.SelectedRows.Count > 0)
{
dataGridView1.Rows.RemoveAt(this.dataGridView1.SelectedRows[0].Index);
}
}
which will add the copied cells to the clip board. Then to paste them, something like:
private void paste2_Click(Object sender, EventArgs e)
{
char[] rowSplitter = { '\r', '\n' };
char[] columnSplitter = { '\t' };
// Get the text from clipboard
IDataObject dataInClipboard = Clipboard.GetDataObject();
string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);
// Split it into lines
string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);
// Get the row and column of selected cell in grid
int r = dataGridView1.SelectedCells[0].RowIndex;
int c = dataGridView1.SelectedCells[0].ColumnIndex;
// Add rows into grid to fit clipboard lines
if (dataGridView1.Rows.Count < (r + rowsInClipboard.Length))
{
dataGridView1.Rows.Add(r + rowsInClipboard.Length - dataGridView1.Rows.Count);
}
// Loop through the lines, split them into cells and place the values in the corresponding cell.
for (int iRow = 0; iRow < rowsInClipboard.Length; iRow++)
{
// Split row into cell values
string[] valuesInRow = rowsInClipboard[iRow].Split(columnSplitter);
// Cycle through cell values
for (int iCol = 0; iCol < valuesInRow.Length; iCol++)
{
// Assign cell value, only if it within columns of the grid
if (dataGridView1.ColumnCount - 1 >= c + iCol)
{
DataGridViewCell cell = dataGridView1.Rows[r + iRow].Cells[c + iCol];
if (!cell.ReadOnly)
{
cell.Value = valuesInRow[iCol+1];
}
}
}
}
}
I use [col+1] because the first item in the list is always a blank (""). Hope this helps someone. It works for me! :D
How to get a contextmenu to appear on right click of a datagridview cell
try this code :
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(1040,518)
$form.KeyPreview = $true
$form.StartPosition = 'centerscreen'
$form.BackColor = 'MidnightBlue'
$form.Add_KeyDown({if($_.KeyCode -eq "Escape"){$form.Close()}})
$form.Text = "VIOC Toolkit 5.4"
$form.Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell_ise.exe")
$form.MinimumSize = New-Object System.Drawing.Size(1040,525)
[System.Windows.Forms.DataGridView] $DataGrid1 = New-Object System.Windows.Forms.DataGridView
$DataGrid1.Location = New-Object System.Drawing.Size(298,29)
$DataGrid1.Dock = "Fill"
$DataGrid1.BorderStyle = 'FixedSingle'
#$DataGrid1.DefaultCellStyle.Font = New-Object System.Drawing.Font $dgfont,$dgfontSize
$DataGrid1.AlternatingRowsDefaultCellStyle.BackColor = 'LightGray'
$DataGrid1.AllowUserToAddRows = $false
$DataGrid1.RowHeadersVisible = $false
$DataGrid1.BackgroundColor = "White"
$DataGrid1.Name="DataGrid1"
$DataGrid1.Text="DataGrid1"
$DataGrid1.ColumnCount = 3
$DataGrid1.Columns[0].Name = 'one'
$DataGrid1.Columns[1].Name = 'two'
$DataGrid1.Columns[2].Name = 'three'
$DataGrid1.Rows.add(@('a', 'b', 'c'))
$DataGrid1.Rows.add(@('d', 'e', 'f'))
#Creation of content click event
$ClickElementMenu=
{
[System.Windows.Forms.ToolStripItem]$sender = $args[0]
[System.EventArgs]$e= $args[1]
$Contentcell=$DataGrid1.Rows[$DataGrid1.CurrentCell.RowIndex].Cells[$DataGrid1.CurrentCell.ColumnIndex].Value
$ElementMenuClicked=$sender.Text
$RowIndex=$DataGrid1.CurrentCell.RowIndex
$ColIndex=$DataGrid1.CurrentCell.ColumnIndex
$result="Click on element menu : '{0}' , in rowindex : {1} , column : {2}, content cell : {3}" -f $ElementMenuClicked, $RowIndex, $ColIndex, $Contentcell;
Write-Host $result
}
#creation menu
$contextMenuStrip1=New-Object System.Windows.Forms.ContextMenuStrip
#creation element1 of menu
[System.Windows.Forms.ToolStripItem]$toolStripItem1 = New-Object System.Windows.Forms.ToolStripMenuItem
$toolStripItem1.Text = "Element 1";
$toolStripItem1.add_Click($ClickElementMenu)
$contextMenuStrip1.Items.Add($toolStripItem1);
#creation element2 of menu
[System.Windows.Forms.ToolStripItem]$toolStripItem2 = New-Object System.Windows.Forms.ToolStripMenuItem
$toolStripItem2.Text = "Element 2";
$toolStripItem2.add_Click($ClickElementMenu)
$contextMenuStrip1.Items.Add($toolStripItem2);
#creation event of mouse down on datagrid and show menu when click
$DataGrid1.add_MouseDown({
$sender = $args[0]
[System.Windows.Forms.MouseEventArgs]$e= $args[1]
if ($e.Button -eq [System.Windows.Forms.MouseButtons]::Right)
{
[System.Windows.Forms.DataGridView+HitTestInfo] $hit = $DataGrid1.HitTest($e.X, $e.Y);
if ($hit.Type -eq [System.Windows.Forms.DataGridViewHitTestType]::Cell)
{
$DataGrid1.CurrentCell = $DataGrid1[$hit.ColumnIndex, $hit.RowIndex];
$contextMenuStrip1.Show($DataGrid1, $e.X, $e.Y);
}
}
})
#***************************************************************#
$form.Controls.Add($DataGrid1)
$form.ShowDialog() | out-null
Context menu not displaying near datagridview cell where right click occurred
Getting the context menu to display next to the last “selected” cell is doable; however, it is not going to be very user friendly. In most cases, when a user “right-clicks” on something a context menu is expected to appear “underneath” wherever the mouse “pointer” was when the user “right-clicked”. What you are describing is moving the context menu “away” from where the mouse “arrow” is located. I am confident most users will not be expecting this.
I am guessing from what you posted… that the user selects multiple cells in the grid, then the user “right-clicks” somewhere on the grid. This would display a context menu (underneath the MOUSE and not move the menu to some selected cell). The context menu would display the “OffLine/OnLine” menu items. Then after the user selects “Online/Offline”, some method would use the “selected” cells in the grid as data to set the cells online or offline. This is about as much as I can decipher from your question.
To help, below are some suggestions. The last line of code in the post….
m.Show(machineGrid, new Point(e.X, e.Y));
The above line moves the context menu to the grids X, Y values using the UI coordinates. This appears to have nothing to do with which cells are “selected”. Yet this will move the context menu somewhere above where the user right clicked... forcing the user to “chase” the context menu.
Lastly, I question the use of the “CellMouseDown” event to do this context menu logic. The DataGridView
has its own “ContextMenuStrip” which you can set. Using the DataGridView’s
ContextMenuStrip
may be an easier approach. Below is an example of setting a DataGridView
named dgv_PlayerPool
with a ContextMenuStrip
as described.
private void SetContexMenu() {
ContextMenuStrip cms = new ContextMenuStrip();
cms.Items.Add("Set OnLine", null, setOnline_Click);
cms.Items.Add("Set OffLine", null, setOffline_Click);
dgv_PlayerPool.ContextMenuStrip = cms;
}
The items add line above, takes a string to display in the menu, an image and finally an event to call when clicked.
The events fired when the user selects a context menu item.
private void setOffline_Click(object sender, EventArgs e) {
MessageBox.Show("SetOffLine");
}
private void setOnline_Click(object sender, EventArgs e) {
MessageBox.Show("SetOnLine");
}
Hope this makes sense.
Right click to select a row in a Datagridview and show a menu to delete it
I finally solved it:
In Visual Studio, create a ContextMenuStrip with an item called "DeleteRow"
Then at the DataGridView link the ContextMenuStrip
Using the code below helped me getting it work.
this.MyDataGridView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown);
this.DeleteRow.Click += new System.EventHandler(this.DeleteRow_Click);
Here is the cool part
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
var hti = MyDataGridView.HitTest(e.X, e.Y);
MyDataGridView.ClearSelection();
MyDataGridView.Rows[hti.RowIndex].Selected = true;
}
}
private void DeleteRow_Click(object sender, EventArgs e)
{
Int32 rowToDelete = MyDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
MyDataGridView.Rows.RemoveAt(rowToDelete);
MyDataGridView.ClearSelection();
}
Opening a context menu on DataGridView
The context menu will popup before the CellMouseClick event is fired so move your code to CellMouseDown instead.
Private Sub DataGridView1_CellMouseDown(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDown
If e.Button = Windows.Forms.MouseButtons.Right Then
If e.ColumnIndex <> -1 And e.RowIndex <> -1 Then
Me.DataGridView1.ClearSelection()
Dim cell = Me.DataGridView1.Item(e.ColumnIndex, e.RowIndex)
Me.DataGridView1.CurrentCell = cell
cell.Selected = True 'Needed if you right click twice on the same cell
DataGridView1.ContextMenuStrip = mnuCell
End If
End If
End Sub
C# DataGridView opening ContextMenu at location of Right Click
Option 1: The most simple solution for showing a context menu for rows is assigning the context menu to RowTemplate.ContextMenuStrip
property of DataGridView:
dataGridView1.RowTemplate.ContextMenuStrip = contextMenuStrip1;
Option 2: Also if you want to select the cell before showing the ContextMenuStrip
, it's enough to handle CellContextMenuStripNeeded
event:
private void dataGridView1_CellContextMenuStripNeeded(object sender,
DataGridViewCellContextMenuStripNeededEventArgs e)
{
if (e.RowIndex > -1 && e.ColumnIndex > -1)
{
dataGridView1.CurrentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
e.ContextMenuStrip = contextMenuStrip1;
}
}
What was your mistake?
You are calculating the mouse position on the DataGridView
in a wrong way. You are using PointToClient
which means this.PointToClient
, while you need to use the method of DataGridView
, for example dataGridView1.PointToClient
:
myContextMenu.Show(dataGridView1,dataGridView1.PointToClient(Cursor.Position));
Just for your information you can simply show ContextMenu
using this code and there is no need to use ContextMenuStrip
.
But I strongly recommend you to use ContextMenuStrip
.
C# DataGridView Right Click to ContextMenu Click Retrieve Cell Value
If you're going with the solution of that post, then note that he's subscribing to the CellMouseDown
event, not the MouseDown
event. This has a different signature.
Also, as of .Net 2.0, you don't need all the delegate wrapping syntax, you can just +=
the function that matches the signature of the event delegate, like so:
// Your updated MouseDown handler function with DataGridViewCellMouseEventArgs
GridView1.CellMouseDown += this.dataGridView_MouseDown;
Then you won't have the error message, and can do what you see in the post.
Right click to select row in DataGridView
Try setting the current cell like this (this will set the CurrentRow
property of the DataGridView
before the context menu item is selected):
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
var dataGrid = (DataGridView) sender;
if (e.Button == MouseButtons.Right && e.RowIndex != -1)
{
var row = dataGrid.Rows[e.RowIndex];
dataGrid.CurrentCell = row.Cells[e.ColumnIndex == -1 ? 1 : e.ColumnIndex];
row.Selected = true;
dataGrid.Focus();
}
}
DataGridView right-click menu/copy example?
You can use ContextMenuStrip to accomplish this.
(Or ContextMenu for pre-VS2k5)
Excerpt from this article:
ContextMenuStrip mnu = new ContextMenuStrip();
ToolStripMenuItem mnuCopy = new ToolStripMenuItem("Copy");
ToolStripMenuItem mnuCut = new ToolStripMenuItem("Cut");
ToolStripMenuItem mnuPaste = new ToolStripMenuItem("Paste");
//Assign event handlers
mnuCopy.Click += new EventHandler(mnuCopy_Click);
mnuCut.Click += new EventHandler(mnuCut_Click);
mnuPaste.Click += new EventHandler(mnuPaste_Click);
//Add to main context menu
mnu.Items.AddRange(new ToolStripItem[] { mnuCopy, mnuCut, mnuPaste});
//Assign to datagridview
dataGridView1.ContextMenuStrip = mnu;
There is more information on the above link.
Related Topics
C# Use System.Type as Generic Parameter
SQL Query Slow in .Net Application But Instantaneous in SQL Server Management Studio
.Net Hashtable VS Dictionary - Can the Dictionary Be as Fast
How to Find If a Native Dll File Is Compiled as X64 or X86
Check for Device Change (Add/Remove) Events
"On Exit" for a Console Application
Invalid Length for a Base-64 Char Array
Bring a Window to the Front in Wpf
C# Store Functions in a Dictionary
Right Click Context Menu for Datagridview
Usercontrol' Constructor with Parameters in C#
Is It Safe to Check Floating Point Values for Equality to 0
Why Doesn't C# Support the Return of References
How to Write to the Console in Colour in .Net
Entity Framework Core 2.0.1 Eager Loading on All Nested Related Entities
How to Limit the Maximum Number of Parallel Tasks in C#
How to Determine If a Type Implements a Specific Generic Interface Type