MouseLeftButtonUpEvent & Bubbling in Canvas - silverlight

I think I'm going crazy...
I have Canvas with event handlers for MouseMove & MouseLeftButtonUp.
However MouseLeftButtonUp is not being fired when it happens with cursor over TextBlock that is inside canvas.
(it fires just fine when I release mouse button in empty space of the canvas)
I tried attaching handler via AddHandler and using regular += syntax, nothing seems to work.
I tried using Canvas.CaptureMouse() but it doesnt seem to work either (CaptureMouse returns true btw).
MouseLeftButtonUp just doesnt want to propagate to it's parent when it happens over TextBlock (or any other element with IsHitTestVisible = true) inside Canvas.
Please help.

First I'd like to say that you are not going crazy. I've seen this before in Silverlight applications. Silverlight has some interesting event strategies. Silverlight events follow a bubble up approach for routed events but not with all events (msdn has some information on this) The events you are listening to are in that list but they are being handled by the TextBlock. Most UIElements have IsHitTestVisible=true so that mouse events and others are captured by the control and not bubbled up to its parent. Setting IsHitTestVisible=false should solve the problem. Other than that I can tell you what I have tried to overcome this issue when needing IsHitTestVisible=true.
Set the event hanlder from the parent on the TextBlock. Downside is you need to do this for every control in your canvas.
Try to fire the event through an extension class. I could not get this one to work cause i couldn't fire events using reflection.

You mentioned you tried AddHandler - did you try the AddHandler overload that accepts two parameters, the second one being "true" to indicate you want to get handled events as well?

Related

WPF TouchUp Event Strange behaivor

My WPF app functions perfectly, but only when using a mouse. Troubles start when using it on a device with a touch screen..
I have a grid that handles MouseLeftButtonUp and TouchUp events.
Now, I press on the grid, it handles related events, then I press on some other control, that other control catches TouchUp event as expected, then TouchUp event is transformed into MouseLeftButtonUp event, which is also something to expect.
However, the newly fired MouseLeftButtonUp event is fired NOT for the control that I pressed on, but for the above mentioned grid! Why does it behave this way?
Thank you in advance...
This is normal behaviour for all RoutedEvents. From the UIElement.MouseLeftButtonUp event page on MSDN:
Although this routed event seems to follow a bubbling route through an element tree, it actually is a direct routed event that is raised and reraised along the element tree by each UIElement.
MSDN provides far more answers and far quicker than Stack Overflow.

WPF: why CaptureMouse may fail?

I have a quite complex view with multiple tabs inside tab control. On one tab there is a control with adorner layer. Adorner layer calling CaptureMouse in MouseLeftButtonDown event handler to capture mouse input. Everything works fine.
But if I switch tabs on the view in particular order and then click on adorner layer it fails to capture mouse input: CaptureMouse() returns false. The same time Mouse.Captured returns null. Control that hosts adorner layer continues to work fine and even able to capture mouse.
Can't provide any code because there are many custom controls in action. In simplified layouts everything works fine.
Any suggestions why CaptureMouse may fail?
If the IInputElement is a UIElement or a UIElement3D, IsVisible and IsEnabled must be true.
If the IInputElement is a ContentElement, there is no IsVisible so just IsEnabled must be true. This is of course at the time you call Mouse.Capture. Also, the PresentationSource for the IInputElement's containing visual must have an IMouseInputProvider.
I think the problem here is either another element immediately taking capture, or IsVisible being false at the time you call Capture.
Make sure that in the MouseLeftButtonUp event handler you're calling ReleaseMouseCapture() otherwise your original adornerlayer will hold on to it.
Also check to ensure that you don't have any controls further up the chain that are also capturing the mouse (you can set handled to true in your adorner layer to prevent that)
Edit: Also make sure IsEnabled is true.

Capture all Click or Touch events recursively in WPF

am pretty new to WPF, but am looking to capture whenever anyone touches inside a window or any child controls.
If I capture the click event for a Window, only the windows inner space capture the click. It's child controls do not.
How do i recursively capture any click/touch event ANYWHERE on the screen in a full size window?
many thanks in advance
The routed event handling implementation in WPF is intended to give all controls in a nested hierarchy a chance to intercept and handle touch & mouse events. However, controls have the ability to prevent children from receiving the event notification.
There's a pretty good explanation of event routing here: http://nui.joshland.org/2010/04/why-wont-wpf-controls-work-with-touch.html
All controls receive a Preview event (for click or touch), and this cannot be prevented. After this, the event is 'promoted' to a regular Mouse/Touch event (touch is handled before click) However, if any control in the hierarchy for the 'click' (_MouseDown in WPF) event handling sets the Handled property on the event args to true, then the event will not be propagated any further.
Unless you are handling touch events or manipulations, or explicitly setting e.Handled = true in your code, then all controls in a nested stack should receive the _MouseDown event.
As noted in the comments below, some controls will set 'Handled = true' which would prevent their containers from receiving corresponding _TouchDown or _MouseDown events. However, they would all receive a PreviewTouch/PreviewMouseDown first.
Also note that handling touch events prevents handling of mouse events.

Preventing WPF event tunneling

I would need to draw lots of WPF-paths. I have set them to children of canvas. Problems is that events are tunneled to path-objects. That slows down the performance. I know overriding preview-method fix the problem, but do I really have to override all preview-methods..
I think you can catch the event in the Canvas and set e.Handled to true.
I found solution. I set path objects's IsHitTestVisible-property to false. Now they doesn't slow down the performance.
Not to resurrect old questions but, if there were e.g. buttons instead of paths, setting IsHitTestVisible to true would have not been ok since it effectively prevents Click and other events.
In my case I had a TabItem with a PreviewMouseMove event and a Button on that very TabItem with a Click event that didn't fire.
The thing is that if you got a tunneling event (like PreviewMouseMove) on a parent control, it will "override" similar events on its child controls.
A possible solution - the one that worked out for me - is picking up a different bubbling event, like MouseMove.
In short, bubbling events propagate to parent elements, while tunneling events propagate to child elements; there are also direct events that do not propagate at all.
More on the topic here.

MouseCapture prevents all mouse based triggers from firing in WPF

I am using CaptureMouse() during a drag and drop operation to make sure I don't miss the MouseUp event, but this seems to prevent any mouse events reaching any other objects on my Canvas. This means that my IsMouseOver based triggers don't work, but I need them to indicate valid locations where the object can be dropped.
Am I doing this wrong, or is there a way of making sure everything on my Canvas still gets mouse events?
Are the elements part of the SubTree of your canvas? or outside of the canvas? If they are within then you could probably use the Capture method that takes a CaptureMode.
Mouse.Capture(elementToCapture, CaptureMode.SubTree);
Alternatively, you should look at the DragDrop class and consider using the Drop event instead?

Resources