I am trying to start a drag and drop on a Button control in WPF. I am using Button because I also want to handle click event.
Adding a Button in XAML and handling the MouseMove event always has e.LeftMouse equal to MouseButtonState.Released.
<Button MouseMove="Button_MouseMove"/>
In the following handler implementation the exception is never thrown.
private void Button_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
throw new Exception("It works!");
}
I noticed the same is true for any control I place inside a Button and try to process MouseMove event.
How do I handle drag and drop from a Button control or any other control inside a button in WPF?
EDIT - Solution based on mm8's answer
The updated XAML is:
<Button PreviewMouseDown="Button_PreviewMouseDown"
PreviewMouseUp="Button_PreviewMouseUp"
PreviewMouseMove="Button_PreviewMouseMove">
</Button>
The updated handler code:
Point startPosition;
double delta = 10;
private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
startPosition = e.GetPosition(this);
}
private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
Point currentPosition = e.GetPosition(this);
if ((currentPosition - startPosition).Length < delta)
throw new Exception("MouseClick");
}
private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point currentPosition = e.GetPosition(this);
double currentDelta = (currentPosition - startPosition).Length;
if (e.LeftButton == MouseButtonState.Pressed && currentDelta >= delta)
throw new Exception("DragAndDrop");
}
You could perhaps handle the PreviewMouseDown event instead of Click:
private void Button_Click(object sender, MouseButtonEventArgs e)
{
//handle click here...
e.Handled = true;
}
XAML:
<Button PreviewMouseDown="Button_Click" MouseMove="Button_MouseMove"/>
I have written event handlers for a PictureBox that is created with my MainForm
The pictureBox is named pictureBoxBackGround.
I add dynamically more pictureBoxes and associate their event handlers to the event handlers of pictureBoxBackGround, because i want the to act the same way.
The event handlers work fine when i move the pictureBoxBackGround, but they doesnt work properly with the new pictureBoxes.
Here are the event handlers:
private void pictureBoxBackGround_MouseDown(object sender, MouseEventArgs e)
{
//Begin Move
m_pointLastMousePos = Cursor.Position;
m_bIsPictureBeingMoved = true;
}
private void pictureBoxBackGround_MouseUp(object sender, MouseEventArgs e)
{
//End Move
m_bIsPictureBeingMoved = false;
}
private void pictureBoxBackGround_MouseMove(object sender, MouseEventArgs e)
{
if(m_bIsPictureBeingMoved == true)
{
PictureBox picboxSelected = sender as PictureBox;
int nHorizontalChange = Cursor.Position.X - m_pointLastMousePos.X;
int nVerticalChange = Cursor.Position.Y - m_pointLastMousePos.Y;
Point pointNewImagePosition = pictureBoxBackGround.Location;
pointNewImagePosition.X = pointNewImagePosition.X + nHorizontalChange;
pointNewImagePosition.Y = pointNewImagePosition.Y + nVerticalChange;
if (pointNewImagePosition.X > 0 &&
pointNewImagePosition.Y > 0)
{
picboxSelected.Location = pointNewImagePosition;
m_pointLastMousePos = Cursor.Position;
}
}
}
This is how i attach them:
picBox.MouseDown += new MouseEventHandler(this.pictureBoxBackGround_MouseDown);
picBox.MouseUp += new MouseEventHandler(this.pictureBoxBackGround_MouseUp);
picBox.MouseMove += new MouseEventHandler(this.pictureBoxBackGround_MouseMove);
It's because you're still using the original picturebox inside the event, for instance this line:
Point pointNewImagePosition = pictureBoxBackGround.Location;
You need to ensure all references to a picturebox inside the events go to the sender, and not to pictureBoxBackGround. So this line should be:
Point pointNewImagePosition = picboxSelected.Location;
I have a form that a user uses to select the level when a Game starts. I want to disable the close button such that a user cannot close the form (The user will click some buttons to select the level).
I have been able to stop the user from closing the form if a button is not clicked using
bool _Next = false;
public Form1()
{
InitializeComponent();
button1.Click += new EventHandler(button_Click);
button2.Click += new EventHandler(button_Click);
button3.Click += new EventHandler(button_Click);
}
void button_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (btn == button1)
{
Level(1);
}
else if (btn == button2)
{
Level(2);
}
else if (btn == button3)
{
Level(3);
}
_Next = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (_Next == true)
{
}
else
{
e.Cancel = true;
}
}
This is quite long. I want to know if there is any way i can just disable or hide the form close button
You can hide the Controls of the form with:
this.ControlBox = false;
The above will remove the maximize, minimize and close button from the right upper corner.
The above is also accessible on the Visual Studio when you select the form itself at the properties tab.
You can override the OnClosing method:
protected override void OnClosing(CancelEventArgs e)
{
if (!_Next)
{
e.Cancel = true;
}
}
You're already disabling the close button. In your FormClosing event you cancel the event:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
This code works perfectly; I just tested it to make sure.
I'm tring to implement a button which have a dropdown menu when checked and this menu is gone when unchecked. My problem is I cannot uncheck the checkbox when it or its menu lost focus.
The checkbox's appearance mode is button.
My code:
private void cbSettings_CheckedChanged(object sender, EventArgs e)
{
if (cbSettings.Checked) {cmsSettings.Show(cbSettings, 0, cbSettings.Height);}
else {cmsSettings.Hide();}
}
I've tried to uncheck the checkBox on contextMenuStrip's VisibleChanged / Closed event but this caused menu not to hide (or hide and show immediately).
The example below does not, of course, include the code you would need for swapping BackGroundImage of the CheckBox to indicate CheckState. The events to "wire-up" should be obvious. Hope this is helpful.
// tested in VS 2010 Pro, .NET 4.0 FrameWork Client Profile
// uses:
// CheckBox named 'checkBox1
// ContextMenuStrip named 'contextMenuStrip1
// TextBox named 'cMenuSelectionInfo for run-time checking of results
// used to position the ContextMenuStrip
private Point cPoint;
// context click ? dubious assumption that 'right' = context click
private bool cmOpenedRight;
// the clicked ToolStripMenuItem
private ToolStripMenuItem tsMIClicked;
private void checkBox1_MouseDown(object sender, MouseEventArgs e)
{
cmOpenedRight = e.Button == MouseButtons.Right;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// positioning the CheckBox like this
// is something in a 'real-world' example
// you'd want to do in the Form.Load event !
// unless, of course, you'd made the CheckBox movable
if(checkBox1.Checked)
{
contextMenuStrip1.Show();
cPoint = PointToScreen(new Point(checkBox1.Left, checkBox1.Top + checkBox1.Height));
contextMenuStrip1.Location = cPoint;
}
else
{
contextMenuStrip1.Hide();
}
}
private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
// assume you do not have to check for null here ?
tsMIClicked = e.ClickedItem as ToolStripMenuItem;
tbCbMenuSelectionInfo.Text = tsMIClicked + " : " + ! (tsMIClicked.Checked);
}
private void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
e.Cancel = checkBox1.Checked;
}
private void contextMenuStrip1_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
if (cmOpenedRight)
{
tbCbMenuSelectionInfo.Text += " : closed because : " + e.CloseReason.ToString();
}
}
I think your approach of unchecking the check box on the context menu's closed event is a good one, what you need is a bit of "event cancelling logic"(c), like this:
private void OnContextClosing(object sender, EventArgs e)
{
_cancel = true;
cbSettings.Checked = false;
_cancel = false;
}
private void cbSettings_CheckedChanged(object sender, EventArgs e)
{
if(_cancel)
return;
if (cbSettings.Checked) {cmsSettings.Show(cbSettings, 0, cbSettings.Height);}
else {cmsSettings.Hide();}
}
This will keep your CheckChanged event from re-checking your checkbox.
I have few columns in my DataGridView, and there is data in my rows. I saw few solutions in here, but I can not combine them!
Simply a way to right-click on a row, it will select the whole row and show a menu with an option to delete the row and when the option selected it will delete the row.
I made few attempts but none is working and it looks messy. What should I do?
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();
}
For completness of this question, better to use a Grid event rather than mouse.
First Set your datagrid properties:
SelectionMode to FullRowSelect
and
RowTemplate / ContextMenuStrip to a context menu.
Create the CellMouseDown event:-
private void myDatagridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
int rowSelected = e.RowIndex;
if (e.RowIndex != -1)
{
this.myDatagridView.ClearSelection();
this.myDatagridView.Rows[rowSelected].Selected = true;
}
// you now have the selected row with the context menu showing for the user to delete etc.
}
}
private void dgvOferty_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
{
dgvOferty.ClearSelection();
int rowSelected = e.RowIndex;
if (e.RowIndex != -1)
{
this.dgvOferty.Rows[rowSelected].Selected = true;
}
e.ContextMenuStrip = cmstrip;
}
TADA :D. The easiest way period. For custom cells just modify a little.
It's much more easier to add only the event for mousedown:
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var hti = MyDataGridView.HitTest(e.X, e.Y);
MyDataGridView.Rows[hti.RowIndex].Selected = true;
MyDataGridView.Rows.RemoveAt(rowToDelete);
MyDataGridView.ClearSelection();
}
}
This is easier. Of cource you have to init your mousedown-event as already mentioned with:
this.MyDataGridView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown);
in your constructor.
All the answers posed in to this question are based on a mouse click event. You can also assign a ContenxtMenuStrip to your DataGridview and check if there is a row selected when the user RightMouseButtons on the DataGridView and decide whether you want to view the ContenxtMenuStrip or not. You can do so by setting the CancelEventArgs.Cancel value in the the Opening event of the ContextMenuStrip
private void MyContextMenuStrip_Opening(object sender, CancelEventArgs e)
{
//Only show ContextMenuStrip when there is 1 row selected.
if (MyDataGridView.SelectedRows.Count != 1) e.Cancel = true;
}
But if you have several context menu strips, with each containing different options, depending on the selection, I would go for a mouse-click-approach myself as well.
base on #Data-Base answer it will not work until make selection mode FullRow
MyDataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
but if you need to make it work in CellSelect Mode
MyDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
// for cell selection
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
var hit = MyDataGridView.HitTest(e.X, e.Y);
MyDataGridView.ClearSelection();
// cell selection
MyDataGridView[hit.ColumnIndex,hit.RowIndex].Selected = true;
}
}
private void DeleteRow_Click(object sender, EventArgs e)
{
int rowToDelete = MyDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
MyDataGridView.Rows.RemoveAt(rowToDelete);
MyDataGridView.ClearSelection();
}
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
MyDataGridView.ClearSelection();
MyDataGridView.Rows[e.RowIndex].Selected = true;
}
}
private void DeleteRow_Click(object sender, EventArgs e)
{
Int32 rowToDelete = MyrDataGridView.Rows.GetFirstRow(DataGridViewElementStates.Selected);
MyDataGridView.Rows.RemoveAt(rowToDelete);
MyDataGridView.ClearSelection();
}
private void dataGridView1_CellContextMenuStripNeeded(object sender,
DataGridViewCellContextMenuStripNeededEventArgs e)
{
if (e.RowIndex != -1)
{
dataGridView1.ClearSelection();
this.dataGridView1.Rows[e.RowIndex].Selected = true;
e.ContextMenuStrip = contextMenuStrip1;
}
}
It is work for me without any errors:
this.dataGridView2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MyDataGridView_MouseDown);
this.dataGridView2.Click += new System.EventHandler(this.DeleteRow_Click);
And this
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var hti = dataGridView2.HitTest(e.X, e.Y);
dataGridView2.ClearSelection();
dataGridView2.Rows[hti.RowIndex].Selected = true;
}
}
private void DeleteRow_Click(object sender, EventArgs e)
{
Int32 rowToDelete = dataGridView2.Rows.GetFirstRow(DataGridViewElementStates.Selected);
if (rowToDelete == -1) { }
else
{
dataGridView2.Rows.RemoveAt(rowToDelete);
dataGridView2.ClearSelection();
}
}
You can also make this a little simpler by using the following inside the event code:
private void MyDataGridView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
rowToDelete = e.RowIndex;
MyDataGridView.Rows.RemoveAt(rowToDelete);
MyDataGridView.ClearSelection();
}
}
See here it can be done using the DataGridView RowTemplate property.
Note: This code isn't tested but I've used this method before.
// Create DataGridView
DataGridView gridView = new DataGridView();
gridView.AutoGenerateColumns = false;
gridView.Columns.Add("Col", "Col");
// Create ContextMenu and set event
ContextMenuStrip cMenu = new ContextMenuStrip();
ToolStripItem mItem = cMenu.Items.Add("Delete");
mItem.Click += (o, e) => { /* Do Something */ };
// This makes all rows added to the datagridview use the same context menu
DataGridViewRow defaultRow = new DataGridViewRow();
defaultRow.ContextMenuStrip = cMenu;
And there you go, as easy as that!
I have a new workaround to come in same result, but, with less code.
for Winforms... That's example is in portuguese
Follow up step by step
Create a contextMenuStrip in your form and create one item
Sign one event click (OnCancelarItem_Click) for this contextMenuStrip
Create a event 'UserDeletingRow' on gridview
and now... you've simulating on key press del from user
you don't forget to enable delete on the gridview, right?!
and finally...