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.
Related
I have UserControl, which contains Canvas (in Grid).
When I just clicked on canvas event PreviewMouseLeftButtonDown or MouseLeftButtonDown works perfectly, but when I set canvas.Background = new ImageBrush(imgs); and try to click on canvas, events doesn't raising. I tried to make same events for grid (canvas parent), but result was the same.
UPD1: canvas has children - rectangle (from System.Windows.Shapes) around cursor, maybe it somehow affect on events.
In wpf there are two possible scenarios where hit testing (clicking with mouse somewhere) is not working. These two are ment to be that way and it is by design. I am talking about when your Background is NULL or when you have the property IsHitTestVisible set to false.
In any other case hit testing/clicking will work.
I assume your background is null somehow. Maybe imgs throws error which will be catched in an empty try/catch block internally at render time.
Tell us is the background property of your canvas null?
There is a nice tool called Snoop which allows you to snoop an wpf app and change properties at runtime. Use that tool to change the background and tell us about the results.
EDIT:
First of all the default value of Canvas Background is null therefore by default you can click as often you wish on Canvas and nothing will happen.
As soon you change the Background to Yellow it clicking will work and your handler will be called.
I have buttons on my Silverlight page where the opacity is bound to one of two properties on my ViewModel. I'm using the button command that changes the properties, in theory to affect all buttons bound to that property, but the only control that gets affected is the button that initiates the command (any one of them).
Any ideas on why the additional bindings don't work?
The whole thing is actually a little more complex where the buttons are on a Control with the bindings as DependencyProperties mapping back to the VM, and the bound properties are going through a ValueConverter.
It sounds like you need to raise the INotifyPropertyChanged.PropertyChanged event for the properties that are changing. This will let the controls that are bound to them know that there is a change and that they need to come back and get the latest value.
I found the problem. The opacity binding wasn't working, but what was happening was the button was disabling itself based on the predicate I had set in the RelayCommand. It looked like the effect I wanted, but only affected the button being pressed because each button was bound to a seperate ICommand.
I changed it to remove change the binding from the OpacityProperty to the IsEnabledProperty, and removed the predicate from the RelayCommand declaration. It all works now as intended.
I don't know why the button would change to a disabled view when it checks the predicate (and finds it false), but never change back if the condition changes. Odd.
I've created a custom panel control and would like to have it respond to a mouse move event, however, when I add an event handler like so:
Private Sub FloatingPanel_MouseMove(ByVal sender As Object,
ByVal e As MouseEventArgs) Handles Me.MouseMove
End Sub
It only responds when I move the mouse over one of the child controls within the panel. I need to have it respond whenever I move the mouse anywhere inside the custom panel.
Update:
I found the following question which gave me a clue:
WPF - how to best implement a panel with draggable/zoomable children?
I can get mouse events on the
GraphCanvas itself only if it has a
background at the point
This led me to simply set the background which appears to have resolved the issue... My question now is, why? Why should I have to set the background in order to receive a mousemove event?
Update 2: The following code is what ultimately solved the problem (See Kent's answer below).
Protected Overrides Function HitTestCore(ByVal hitTestParameters As System.Windows.Media.PointHitTestParameters) As System.Windows.Media.HitTestResult
Return New PointHitTestResult(Me, hitTestParameters.HitPoint)
End Function
Thank you,
Matt
For the purposes of hit testing, WPF's default hit testing logic has two modes of transparency. One is transparent both visually and to hit testing (#00000000 or by not setting a background at all), the other is transparent only visually and does not preclude hit testing (##00ffffff). You want the latter.
I believe you could also override UIElement.HitTestCore in your custom Panel such that there is no dependency on having the background set.
I actually suspected this might have been the issue here; If the background of a control is null and there is no other subcomponent there your mouse is not moving across the control but accross the control behind it, so it makes sense that you do not get a mouse event from that (it is not very expected though because the bounds of the control may envelope the area).
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?
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?