I've been trying to work with the mouse event handlers. Using MouseDown only seems to work with the right mouse button. And PreviewMouseLeftButton doesn't activate the MouseMove event until I release the left button.
So this code:
private void NewButton_MouseDown(object sender, MouseButtonEventArgs e)
{
var test = e.LeftButton;
var test2 = e.RightButton;
if (!bButtonIsDown)
{
bButtonIsDown = true;
Button mover = (Button)sender;
pntEnterPoint = e.GetPosition(this.cnvsLinkScreen);
cnvsLinkScreen.MouseMove += CnvsLinkScreen_MouseMove;
cnvsLinkScreen.MouseUp += CnvsLinkScreen_MouseUp;
spMover = (StackPanel)((Button)sender).Parent;
pntPreviousPoint.X = Canvas.GetLeft(spMover);
pntPreviousPoint.Y = Canvas.GetTop(spMover);
}
}
private void NewButton_MouseMove(object sender, MouseEventArgs e)
{
Button mover = (Button)sender;
StackPanel spMover = (StackPanel)((Button)sender).Parent;
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
// Inititate the drag-and-drop operation.
FindChild<StackPanel>(cnvsLinkScreen, "CSVImport");
pntEnterPoint = e.GetPosition(this.cnvsLinkScreen);
Canvas.SetLeft(spMover, pntEnterPoint.X + 1);
Canvas.SetTop(spMover, pntEnterPoint.Y + 1);
}
}
Works but with right button only. When enabling the event handler with:
newButton.MouseDown += NewButton_MouseDown;
That event handler will not get touched with the left mouse button, which I think is odd.
I've done a good amount of reading out there and people refer to thePreviewMouseLeftButtonDown event handler but when I use that in place (same code) the cnvsLinkScreen.MouseMove += CnvsLinkScreen_MouseMove doesn't fire until I let go of the left mouse button (button up) then the StackPanel drags until I click and drop it.
I set breakpoints and see that the event handler is getting set, but it's just not working until after the left button is released. Clearly I'm missing something with the event handlers on this.
Why isn't the MouseDown event handler not even firing with a left mouse button down; only a right mouse button down?
This has to do with Routed Events. Unlike with normal events, a routed event can be marked as handled, after which no further handlers for that event will be called.
MouseDown and MouseMove are bubbling routed events, meaning they start at the deepest elements (the ones inside the button) and then "bubble" their way up, through their parents, toward the Window. Any parent can register a handler for these events and it will be called when the event reaches that parent's level. However if any child marks the event as handled, the event will never reach the parent and the parent's handler will never be called.
This is what's happening here. Button has a handler for MouseDown internally. When Button decides it has been clicked, it raises its own Click event and marks MouseDown as handled. Button also seems to handle MouseMove, but only while a click is in progress. This is why your event handlers don't get called during a left-click, because left-click triggers a "click" which ends up handling those events before they make it out of the Button.
PreviewMouseDown and PreviewMouseMove, on the other hand, are both tunneling routed events, meaning they start from the broadest parent (the Window) and work their way inwards toward the exact point of the cursor. Tunneling events happen before bubbling events; the mouse input first tunnels in toward the cursor, then bubbles back up.
If you attach event handlers to PreviewMouseDown and PreviewMouseMove instead of MouseDown and MouseMove, you will see all the mouse input you expect.
Funny side note: you can actually play the same trick on Button that Button is playing on you. If you mark PreviewMouseDown as handled before it gets inside the Button, then it will never raise its Click event.
Related
I have a UserControl (let's call it "PresentationCell") which contains a label, and an PictureBox.
In another control, which is using this PresentationCell, I have added an event
presentationCell.GotFocus += OnFocus;
private void OnFocus(object sender, EventArgs e)
{
if (sender is PresentationCell current)
current.BackColor = Color.Azure;
}
This will not be fired, if I click / focus on the Label or PictureBox that is within the PresentationCell.
How can I make it fire, when just something within the PresentationCell is in focus?
The problem here is, that the Label and PictureBox controls aren't selectable controls, so they aren't able to receive focus from mouse clicks.
What you could to instead, is to handle the mouse click event and check if you have hit the PresentationCell. If the PresentationCell is hit you can programatically set the focus like so:
hitPresentationCell.Focus();
This will then fire the GotFocus event.
In your OnFocus method you will have to switch the focus to another control or the event will fire endlessly.
I have seen that many users have asked how to make a clickable image in WPF.
Image has Mouseup event. It works like Button click event as I understand.
Is there any difference in Image Mouseup event and Button click event?
Mouseup event, user can click somewhere else on the screen and hold down the click button and move the pointer to Mouseup element, and then release the mouse.
Click event requires both the mousedown and mouseup event to happen.
The MouseUp can happen in a different control from MouseDown.
A Button can also be bound to a Command and thus separating your logic from the UI.
I have a UserControl defined such that:
UserControl
TextBox
Button (Clear)
I have a GotFocus handler on the UserControl so that whenever it gets focus, it calls TextBox.Focus(). The problem I am running into is that If I click the clear button, it clears the text and then refocuses to the textbox, triggering two GotFocus events on my control. I want this to act as either:
One GotFocus event
One GotFocus event (button), One LostFocus event(button), One GotFocus event (textbox)
I have played with FocusManager.IsFocusScope to no avail. Is there even a way to trigger a manual LostFocus right before I call Textbox.Focus?
In your GotFocus event you can check whether the mouse is over the clear button and whether the left mouse button is pressed, in such a case you can ignore the call to TextBox.Focus():
private void UserControl_GotFocus(object sender, RoutedEventArgs e)
{
if ((this.clearButton.IsMouseOver && Mouse.LeftButton == MouseButtonState.Pressed) == false)
{
this.textBox.Focus();
}
}
Is it possible to prevent mouse events when a window is activated?
For example, I have a C# window and I change the focus to something else such as a browser. When I reactivate the c# window by clicking on it, I don't want any mouse events to be executed. The first click on the window should just activate it. Mouse Events are only fired if the window is already activated.
An event will be fired then a user clicks on your wpf controll but why don't you just handle the event?
Subscribe to the event and prevent it to bubble up the visual tree:
private void Panel_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
Have a look at this link it describes the event bubble and tunneling in WPF.
I have a textbox in a groupbox, both with double click events. When I double click in the textbox both events are triggered.
How do I stop clicks in the textbox from passing through to the groupbox? I've tried putting "e.Handled = true;" at the end of the textbox_DoubleClick event but this makes no difference.
Because WPF uses a "tunneling / bubbling" model of event propagation, most events begin bubbling UP from the bottom of the visual tree. If you want to catch an event on the way down, there are Preview versions of the events that tunnel downwards. For example:
PreviewMouseDoubleClick
Set e.Handled = true in there.
In your GroupBox's DoubleClick event you could check the value of e.OriginalSource and if that value is not the GroupBox, ignore the event
private void TabItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is GroupBox)
{
// Your code here
}
}
I believe ClickEvents are actually Direct Events, and not Tunneled/Bubbled events, so setting e.Handled in one won't cancel the other.
Per MSDN Site for MouseDoubleClick
Although this routed event seems to follow a bubbling route through an
element tree, it actually is a direct routed event that is raised
along the element tree by each UIElement.
you should handle e.Handled in the PreviewDoubleClick because tunneled events happens before bubbled up ones.
also why would you need to handle that event in both textbox and groupbox ? as it is getting fired in both because 2 separate events are getting fired.