I read this good article about Routed Events, and I understood why we need sometimes bubble Events and sometime we need tunnel Events.
What I didn't understand is, when we use the tunnel Event, why after it is handled or reached to the source element, still the bubble event is launched?
Thanks in advance!
The article says that if you put an image on a button, and that image is clicked, the tunnel event for that image will fire. But it is highly likely that you would also want to handle that click as if the button itself was clicked, so a bubble event is also fired which bubbles up to the click event on the button itself (because the button owns the image), so that you can treat the image click like a button click, using the usual event handler for the button.
I would also like to add that the event for both (Tunnel and Bubble) are different.
For tunnel, we use PreviewXXX (eg: PreviewMouseDown) and for bubble event we use XXX (eg: MouseDown) event.
By sequence, Tunnel event gets fired first starting from the root of the application and ends at the source. And the Bubble event is triggered.
It makes perfect sense to have both these events.
Related
I am working on a windows store application and I want to be able to drag between buttons so that the originally pressed button becomes deactivated and the newly "dragged onto" button becomes activated but I can't seem to get this to work.
I have 2 Buttons inside a StackPanel and the events I have on them are:
PointerPressed
PointerEntered
PointerReleased
PointerExited
PointerCanceled
PointerCaptureLost
PointerPressed and PointerEntered share the same event handler and the rest (the "deactivation" events) share the same event handler.
If I press one button my "activated" event handler is triggered and if I drag off it my "deactivated" event handler is triggered but if I then drag onto the second button the "activated" event handler isn't triggered again.
Strangely, if I start by dragging from off the StackPanel onto one of the buttons the "activated" event handler is triggered. I assume that it is something to do with the internal pointer management stuff but can't seem to find a workaround.
Does anyone know why this is happening and how I can get it to work how I want?
Thanks for your time.
Edit
Okay I've been researching some stuff and I've come across CapturePointer() and ReleasePointerCapture() but this seems to be broken - If I capture the pointer, when I take my finger off the screen, PointerReleased doesn't even get hit.
I've also realized why the "dragging from off the SP onto one of the buttons causes it to 'activate'" - this is because when a button is pressed it doesn't route its event but fires a Click event - meaning the same pointer cannot fire a PointerEntered event of another button, but if it starts outside a Button it will trigger PointerEntered.
This doesn't get me much further but it is a little extra info :)
The concept of Button is a bit unique in regard to mouse capture and how dragging away from it happens. In your scenario I'm not sure if the event model around Button will work correctly for you. On Button, when a pointer is depressed (mouse) it has capture until it is released. This is not the same for touch where a press and drag away is different because in touch there isn't any explicit capture unless you create it.
So what you are hitting is going to be a slight conflict between mouse/touch interactions anyway using Button -- using some other UI element (not sure if you have a styled button) should get you what you want.
I am playing around with mouse events and I realized there are a bunch of events but I have no idea when to use which one.
There is the Click event, MouseDown event, PreviewMouseDown, PreviewLeftButtonMouseDown, LeftButtonMouseDown.
What are the differences between then? They all do the same and that is notifying once mouse being pressed.
When shall I use which for what?
Click event : The user has clicked the element and released the button
MouseDown event: The user has pressed the mouse button (before releasing it). Click happens to be called if the user has both pressed and release it on the same element.
PreviewMouseDown : same as mousedown, except it is a tunnel event. It is called on parent function first, then tunneled to the child container while mousedown bubbles upwards (on child container first, and then on parent containers).
LeftButtonMouseDown : Called when left mouse button is pressed
PreviousLeftButtonMouseDown : I am not sure about this event. Could not find it. Did you mean PreviewLeftButtonMouseDown?
I'm displaying a Popup in response to a button click (popup.IsOpen = true;). The popup contains a ComboBox, and when I click an item in the combobox, one of the things the SelectionChanged event does is to hide the popup.
The Popup appears over a DataGrid that I also have on my page, and I'm finding that the mouse-click on the combobox is also being picked up by a MouseUp event that I've got on the DataGrid. Any idea what's going on?
The MouseUp Event has a routing strategy of type Bubbling. Events that use this type of strategy get passed up the chain to parent controls. Since the Popup is a child of the DataGrid, the event will "bubble" up to the DataGrid. If you would rather the event not bubble, you can try using PreviewMouseUp, which has a Tunneling routing strategy, and will "tunnel" down the chain to child controls. Here is a decent overview of Routing Strategies.
I've hit the same issue. Oddly, it doesn't happen when the code is run in the debugger - it only happens in the release version. It really seems to be a bug in WPF. Trying to catch the click and set the event to handled doesn't work.
My workaround is to, when the popup opens, to tell the control underneath to ignore the click.
In my surface application I have a SurfaceWindow with a SurfaceUserControl on. On the SurfaceUserControl I have a SurfaceButton but the ContactUp (and down) event is not fired. The ContactHoldGesture event is fired though.
Any ideas?
Could you include some code to reproduce? Where are you subscribing to those events?
Most likely what's happening is the contact up and down events are being handled by the button, so they don't fire at the usercontrol level. Try looking at the previewcontactup and previewcontactdown events.
ContactUp and ContactDown are handled by the button itself - that's why the events never get to your code. If you really want to intercept these events, use PreviewContactUp/PreviewContactDown instead. What you probably really need though is to just handle the Click event on the button. Adjust the ClickMode property of the button if you want to change what causes the Click event to be raised.
I have a button which launches a "modal dialog" - it just creates a transparent grid covering everything, with the "dialog" created on top of that.
However I have a strange issue - if I double/triple click the button really fast (or add some delay in the event code), the button click event is executed multiple times, creating multiple overlapping modal dialogs. If the first action in my event is to disable the button (IsEnabled=false) it seems to prevent this.
My guess is that Silverlight is being multithreaded with input - it is not only recording the second click in another thread (while the button's click event is running), but it is jumping the gun by evaluating which control should be the target before the previous event has finished executing. Even though that event alters what control is at those mouse coordinates, it doesn't matter.
Does anyone know anything about this behavoir, or a way around it? If I have something like a save window, where the user clicks a save button, a blocking grid ("Saving...") is placed up while it saves, and then the whole "window" is closed, I'd like to avoid the user being able to queue up multiple save event clicks (this could lead to unpredictable program behavoir).
If you've ever worked with WinForms or WPF, this is expected behavior. Your button is broadcasting its Click event until your modal dialog covers it up. Unfortunately, there is some amount of time between your first click and when the modal dialog covers the button which allows multiple clicks to the original button.
You have two solution choices:
Disable the button after the first click and then re-enable after the modal dialog returns. You've already mentioned that this works.
Write code in the Event Handler of the button to determine if a modal dialog is already being displayed. This way, you're putting the responsibility in one location rather than splitting it up (disabling and re-enabling the button). This would be my preferred solution.
I think what you're seeing is the behaviour of Silverlight's routed events.
You can set the Handled property of the event arguments to true to prevent the event from bubbling.