dataGridView Context menu function - c#

I have added this code to my forum:
private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ContextMenu a = new ContextMenu();
a.MenuItems.Add(new MenuItem("Google"));
a.MenuItems.Add(new MenuItem("Yahoo"));
int currentMouseOverRow = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (currentMouseOverRow >= 0)
{
a.MenuItems.Add(new MenuItem(string.Format("", currentMouseOverRow.ToString())));
}
a.Show(dataGridView1, new Point(e.X, e.Y));
}
}
private void dataGridView1_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
currentMouseOverRow = e.RowIndex;
}
private void dataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
currentMouseOverRow = -1;
}
But how do I add the function to the context menu option?
For google,
Process.Start("https://www.google.com");
For yahoo,
Process.Start("https://www.yahoo.com");
etc.

Why not add your ContextMenu right when your Form loads rather than every time that the user right click your DataGridView which means that you have to add the Context Menu every time the user rights click your DatGridView.
Secondly, instead of ContextMenu make a ContextMenuStrip instead which more at home with DataGridView. So, your code would look like:
ContextMenuStrip a = new ContextMenuStrip();
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
Image img = null;
a.Items.Add("Google", img, new System.EventHandler(ContextMenuClick));
a.Items.Add("Yahoo", img, new System.EventHandler(ContextMenuClick));
dataGridView1.ContextMenuStrip = a;
}
Then your EventHandler would look like this:
private void ContextMenuClick(Object sender, System.EventArgs e)
{
switch (sender.ToString().Trim())
{
case "Google":
Process.Start("https://www.google.com");
break;
case "Yahoo":
Process.Start("https://www.yahoo.com");
break;
}
}
And your DataGridView Mouse Click handler would look this:
void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
int currentMouseOverRow = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (currentMouseOverRow >= 0)
{
a.Items.Add(string.Format("", currentMouseOverRow.ToString()));
}
a.Show(dataGridView1, new Point(e.X, e.Y));
}
}

You have to use ClickEvent for your menu items:
//menu items constructor
a.MenuItems.Add(new MenuItem("Google", new System.EventHandler(this.MenuItemClick)));
a.MenuItems.Add(new MenuItem("Yahoo", new System.EventHandler(this.MenuItemClick)));
private void MenuItemClick(Object sender, System.EventArgs e)
{
var m = (MenuItem)sender;
if (m.Text == "Google")
{
Process.Start("https://www.google.com");
}
}

Related

How to display the ContextMenuStrip when item is selected in a list box c# .net

I'm trying select an item from list box when is right clicked and show the ContextMenuStrip to display my options available, but when I click everywhere in the control (list box) is showing the ContextMenuStrip.
This is what I have in code:
private void lbSMTPEmails_MouseDown(object sender, MouseEventArgs e)
{
int SelectedIndex = lbSMTPEmails.IndexFromPoint(e.X, e.Y);
if (SelectedIndex == -1)
lbSMTPEmails.ContextMenuStrip.Hide();
else
{
lbSMTPEmails.SelectedIndex = SelectedIndex;
lbSMTPEmails.ContextMenuStrip.Show();
}
}
do you have any idea how to solve this?
Use opening event of ContextMenuStrip
void cms_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
int SelectedIndex = lbSMTPEmails.IndexFromPoint( lbSMTPEmails.PointToClient(Cursor.Position) );
if (SelectedIndex == -1)
e.Cancel = true;
else
{
lbSMTPEmails.SelectedIndex = SelectedIndex;
}
}
I did by this way and it worked!
private void listbox_MouseDown(object sender, MouseEventArgs e)
{
ShowMenuStrip = listbox.IndexFromPoint(e.Location) >= 0; //This is a global bool variable
if (ShowMenuStrip)
listbox.SelectedIndex = listbox.IndexFromPoint(e.Location);
else
listbox.SelectedIndex = -1;
}
private void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
{
e.Cancel = !ShowMenuStrip;
}

Unable to drag and drop text from DataGridView to TextBox C#

I have been using code that others online have supplied but for some reason it won't let me drag items from the datagridview to the textbox. I highlight a row in the dataGridView and try to drag it to the textbox but nothing happens. I have also enabled the drop property for the textBox but still no difference. Here's the code that I am using:
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y);
if (info.RowIndex >= 0)
{
if (info.RowIndex >= 0 && info.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[info.RowIndex].Cells[info.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
Here is a small sample that i have done to give you an idea on how to do this... works perfectly for me. I used WinForms here. If WPF, there may be some more events you will need to register to in order for the drag+drop to register...
Note that you will want to add more code here and there to perform what you really want to do when you drag an item from one control to the other.
public partial class Form1 : Form
{
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private DataGridViewRow draggedrow;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<StringValue> Items = new List<StringValue>() { new StringValue("1"), new StringValue("2"), new StringValue("3"), new StringValue("4"), new StringValue("5"), new StringValue("6") };
this.dataGridView1.DataSource = Items;
}
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
DragDropEffects dropEffect = dataGridView1.DoDragDrop(
dataGridView1.Rows[rowIndexFromMouseDown],
DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
// Remember the point where the mouse down occurred.
// The DragSize indicates the size that the mouse can move
// before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)),
dragSize);
this.draggedrow = this.dataGridView1.CurrentRow;
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
this.textBox1.Text = (string)this.draggedrow.Cells["Value"].Value;
}
}
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
can't you use DataGridViewCellMouseEventArgs e instead of hittest for getting row index in dataGridView1_CellMouseDown. below is your code modified hope this helps
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (e.RowIndex >= 0)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}

How to Drag, Drop and Resize Label on a Panel at runtime? C#, winForms

I have this code for dragging on a Panel but its not doing the thing.
I have to choose if I will just Drag&drop or Resize.
I think theres something wrong with my code here in form load.
Anyway I have 5 labels here and a panel named as label1, label2, label3, label4, label5 on panel1.
private void form_Load(object sender, EventArgs e)
{
//for drag and drop
//this.panel1.AllowDrop = true; // or Allow drop in the panel.
foreach (Control c in this.panel1.Controls)
{
c.MouseDown += new MouseEventHandler(c_MouseDown);
}
this.panel1.DragOver += new DragEventHandler(panel1_DragOver);
this.panel1.DragDrop += new DragEventHandler(panel1_DragDrop);
//end of drag and drop
}
void c_MouseDown(object sender, MouseEventArgs e)
{
Control c = sender as Control;
c.DoDragDrop(c, DragDropEffects.Move);
}
void panel1_DragDrop(object sender, DragEventArgs e)
{
Control c = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
lblResizeAmtWord.Visible = false;
if (c != null)
{
c.Location = this.panel1.PointToClient(new Point(e.X, e.Y));
//this.panel1.Controls.Add(c); //disable if already on the panel
}
}
void panel1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
I used the MouseDown, Up and Move Event of the Control I want to move. Let's say my control name is ctrlToMove.
private Point _Offset = Point.Empty;
private void ctrlToMove_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_Offset = new Point(e.X, e.Y);
}
}
private void ctrlToMove_MouseUp(object sender, MouseEventArgs e)
{
_Offset = Point.Empty;
}
private void ctrlToMove_MouseMove(object sender, MouseEventArgs e)
{
if (_Offset != Point.Empty)
{
Point newlocation = ctrlToMove.Location;
newlocation.X += e.X - _Offset.X;
newlocation.Y += e.Y - _Offset.Y;
ctrlToMove.Location = newlocation;
}
}

DGV DragDrop - row disappearing

I'm attempting to write some code to allow the users of my application to drag and drop rows in a DataGridView to reorder them. The problem is, the row that is being dragged disappears when it's dropped - so dragging and dropping has the effect of just removing that row. Here is my code:
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private void grdCons_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
if (dragBoxFromMouseDown != Rectangle.Empty && !dragBoxFromMouseDown.Contains(e.X, e.Y))
{
DragDropEffects dropEffect = grdCons.DoDragDrop(grdCons.Rows[rowIndexFromMouseDown], DragDropEffects.Move);
}
}
}
private void grdCons_MouseDown(object sender, MouseEventArgs e)
{
rowIndexFromMouseDown = grdCons.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
Size dragSize = SystemInformation.DragSize;
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize);
}
else
{
dragBoxFromMouseDown = Rectangle.Empty;
}
}
private void grdCons_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void grdCons_DragDrop(object sender, DragEventArgs e)
{
Point clientPoint = grdCons.PointToClient(new Point(e.X, e.Y));
rowIndexOfItemUnderMouseToDrop = grdCons.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
if (e.Effect == DragDropEffects.Move)
{
DataGridViewRow rowToMove = e.Data.GetData(typeof(DataGridViewRow)) as DataGridViewRow;
grdCons.Rows.RemoveAt(rowIndexFromMouseDown);
grdCons.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
}
}
At a guess, the Insert on the DGV on the DragDrop event isn't working.
Here is a cleaned up version of your code that works:
public Form1()
{
InitializeComponent();
grdCons.Rows.Add(7);
for (int i = 0; i < grdCons.Rows.Count; i++)
{
grdCons.Rows[i].Cells[0].Value = i;
grdCons.Rows[i].Cells[1].Value = "Cell " + i;
}
grdCons.AllowDrop = true;
grdCons.AllowUserToAddRows = false;
grdCons.AllowUserToDeleteRows = false;
grdCons.MouseMove += new MouseEventHandler(grdCons_MouseMove);
grdCons.MouseDown += new MouseEventHandler(grdCons_MouseDown);
grdCons.DragOver += new DragEventHandler(grdCons_DragOver);
grdCons.DragDrop += new DragEventHandler(grdCons_DragDrop);
}
private int rowIndexFromMouseDown;
private void grdCons_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
grdCons.DoDragDrop(grdCons.Rows[rowIndexFromMouseDown], DragDropEffects.Move);
}
}
private void grdCons_MouseDown(object sender, MouseEventArgs e)
{
rowIndexFromMouseDown = grdCons.HitTest(e.X, e.Y).RowIndex;
}
private void grdCons_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void grdCons_DragDrop(object sender, DragEventArgs e)
{
Point clientPoint = grdCons.PointToClient(new Point(e.X, e.Y));
int targetIndex = grdCons.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
if (e.Effect == DragDropEffects.Move)
{
DataGridViewRow rowToMove = e.Data.GetData(typeof(DataGridViewRow)) as DataGridViewRow;
grdCons.Rows.RemoveAt(rowIndexFromMouseDown);
grdCons.Rows.Insert(targetIndex, rowToMove);
}
}
The problem lies in grdCons_DragDrop(). Because you mentioned the DGV is bound to a DataTable calling grdCons.Rows.Insert(targetIndex, rowToMove) will trigger an InvalidOperationException. When a DGV is data-bound you need to manipulate the DataSource rather than the DGV. Here's the correct way to call grdCons_DragDrop().
private void grdCons_DragDrop(object sender, DragEventArgs e)
{
DataTable tbl = (DataTable)grdCons.DataSource;
Point clientPoint = grdCons.PointToClient(new Point(e.X, e.Y));
int targetIndex = grdCons.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
if (e.Effect == DragDropEffects.Move)
{
DataRow row = tbl.NewRow();
row.ItemArray = tbl.Rows[rowIndexFromMouseDown].ItemArray; //copy the elements
tbl.Rows.RemoveAt(rowIndexFromMouseDown);
tbl.Rows.Insert(targetIndex, rowToMove);
}
}

How do I correctly position a Context Menu when I right click a DataGridView's column header?

I would like to extended DataGridView to add a second ContextMenu which to select what columns are visible in the gird. The new ContextMenu will be displayed on right click of a column's header.
I am having difficulty get the correct horizontal position to show the context menu. How can I correct this?
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.ColumnHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(ColumnHeaderMouseClick);
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
}
Here is a very simple way to make context menu appear where you right-click it.
Handle the event ColumnHeaderMouseClick
private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
contextMenuHeader.Show(Cursor.Position);
}
contextMenuHeader is a ContextMenuStrip that can be defined in the Designer view or at runtime.
To get the coordinate of the mouse cursor you could do this.
ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position));
Have you tried using the Show overload that accepts a control and a position?
For example:
contextMenuStrip.Show(dataGrid, e.Location);
Edit: Full example
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid, e.Location);
}
}
}
}
e.Location does not show the popup menu at the correct coordinates, instead just use the MousePosition property as follows:
ContextMenuStrip.Show(MousePosition)
or, explicitely
ContextMenuStrip.Show(Control.MousePosition)
The position returned is relative to the cell. So we have to add that offset.
private void grdView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var pos = ((DataGridView)sender).GetCellDisplayRectangle(e.ColumnIndex,
e.RowIndex, false).Location;
pos.X += e.X;
pos.Y += e.Y;
contextMenuStrip.Show((DataGridView)sender,pos);
}
}
Finally this worked for me.
ContextMenu.Show(myDataGridView, myDataGridView.PointToClient(Cursor.Position));
Calling Show twice will get you the exact location of the cursor. This answer is for those whom are unable to get the result with all above answers.
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(dataGrid, e.Location));
contextMenuStrip.Show(Cursor.Position);
}
}
Where I was going wrong was that DataGridViewCellMouseEventArgs returns the location/x,y of where the mouse clicked within the column header. Instead I need to use HitTest in the grid's MouseDown event for a hit on the column headers and then convert the position of the hit from the gird co-ordinates to the screen co-ordinates.
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
//dataGrid.ColumnHeaderMouseClick += ColumnHeaderMouseClick;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid.PointToScreen(e.Location));
}
}
}
}
You were nearly right. You just need to the apply the PointToScreen method to the calling control:
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(((DataGridView)sender).PointToScreen(e.Location));
}
}
I think this is the most elegant solution, because it uses only the ColumnHeaderMouseClick arguments and not Cursor.Position.

Categories

Resources