Closed mjracca closed 5 years ago
@mjracca Thanks for the detailed question. I'm going to ask @likuba to see if there is possibly something that can help with your specific scenario. It may take a while as it may touch other parts of the system besides Windows.UI.Composition.
Thanks!
Testing around, our main issue is that the ScrollViewer intercepts all the pointers events, so we can't even make our custom solution. The only way would be to intercept every pointer and basically implement the ScrollViewer from scratch. Of course, we don't want this.
An alternative solution could be if somehow we could intercept the pointers, but then "transfer" them to the ScrollViewer when we decide it should scroll or pan, or to another XAML element. That could also help, but we couldn't find anything like it.
Any tip or alternative solution would be really helpful!
Hi @mjracca ,
So I assume you are trying to hook the PointerPressed event on ScrollViewer and you are not seeing the event fire? If that is true, then it usually means that your ManipulationMode property on the ScrollViewer is set to something other than System and therefore the events are not being routed to the ScrollViewer. Can you check the value for ManipulationMode?
@mikehenderlight yes, we have ScrollViewer's ManipulationMode set to System. PointerPressed isn't the issue, but PointerMoved and PointerExited. This events are not being fired when you are zooming/panning the ScrollViewer (it's easier to see this when using touch input).
Hmm, that should work. Did you try to build a small repro by just using a ScrollViewer that contains and empty InkCanvas? When I did that, PointerMoved fired fine for me. It may help to tease out the problem.
Sure! Here is a small repro: ScrollViewerEvents.zip
I used a Canvas instead of an InkCanvas (it doesn't work either) because this is how we use it.
News?
Sorry, I was out a couple of days last week. So when you run your repro app, are you not getting the pointer events raised at all? When I run your app, I see PointerPressed and PointerMoved, etc. Granted, I am running a newer build than you are.
We are testing on the latest Fast ring build, and we are not receiving the PointerMoved and PointerRelease
@mikehenderlight unless the behavior is changed in your build, PointerMoved
and PointerReleased
events won't be raised within a ScrollViewer
.
PointerPressed
gets raised properly because it happens prior to the scrolling. As soon as the ScrollViewer
starts to scroll, all events get eaten by it.
Yes! That's exactly what happens.
Any way to make it work, at least low level? We need more control over the pointers.
I tried calling ScrollViewer.CancelDirectManipulations()
to take back control when there's more than one fingers pressed, but this only works if I put down two fingers at the exact same time. If I press with one finger first, the ScrollViewer
will start scrolling so the second finger press won't be raised.
I too would love to know if there's any solution to this...
Did you try adding the events with the this.AddHandler(PointerMoved, new PointerEventHandler(pointerMovedHandler), true);
syntax?
Yes, still the same, no event
Can you try the combination of CancelDirectManipulations() and TryStartDirectManipuation()?
private void PrintTouchEvent(PointerRoutedEventArgs e, string eventName)
{
scrollviewer.CancelDirectManipulations();
TryStartDirectManipulation(e.Pointer);
if (e.Pointer.PointerDeviceType == PointerDeviceType.Touch)
System.Diagnostics.Debug.WriteLine(eventName);
}
scrollviewer.CancelDirectManipulations()
will only block the ScrollViewer (and raise PointerMoved) if using two fingers at the same time, as @JustinXinLiu said. If you only use one finger, the ScrollViewer will pan normally, and won't raise PointerMoved. If you touch with one finger and move a little before touching with the other finger, then the ScrollViewer will pan and zoom normally.
Taking those limitations into account, we can't use this to solve our issue.
Ok, so I figure out what was happening. It appears that PointerPressed was being called before DirectManipulationStarted. If I CancelDirectManipulations when the event DirectManipulationStarted raises, then I almost can block the ScrollViewer all the time.
I will try some experiments to see if this could work and write you back. Thanks!
Testing a little further, we are not being able to resume scrolling once canceled.
pointer entered - id: 1306 pointer pressed - id: 1306 DirectManipulationStarted => CancelDirectManipulations: True pointer entered - id: 1306 pointer moved - id: 1306 => TryStartDirectManipulation: False
how can we make TryStartDirectMaipulation to work ?? :dizzy_face:
News? How could we make this work?
I am looping in someone else that may be able to help...Stay tuned.
The ScrollViewer control has to be the most mysterious control in existence 😛. I really wish every low-level detail of exactly how it works was documented on MSDN.
Over a year later and this is still open? Did anyone solve this?
Not really 😞
I made some slight changes to your simple repro app.
I believe this will allow you to intercept the events to figure out whether you need to handle it or pass it on to the system to handle the panning/zooming. Give it a try and let me know if it addresses your issue.
Closing this one out due to inactivity--please re-open if the solution posted above is insufficient.
So glad @micahl 's workaround works. I've spent countless hours trying different workarounds.
It's 2021 and CancelDirectManipulations() still doesn't work within CancelDirectManipulations() as one may reasonably expect. I'm using Microsoft.UI.Xaml 2.6-prerelease.
It's 2023, and I somehow ended up in this thread. I skipped to the very last comment, and it somewhat resonated with my experience. Then I realized I myself wrote it in 2021. Jeez, hello from the future. I'm sure I'll be here again in a few years.
The question
We need to detect two finger gestures (pan and pinch) over a ScrollViewer, is there any way to do this?
The context
We have multiple issues when trying to pan and zoom a ScrollViewer which contains multiple elements. This elements can be dragged as well. We don't want to select the elements first to move them around as others apps, since we value the speed it give us like this.
Here is an normal example of our canvas (it can be much more dense than this):
Errors cases
I have drawn 4 examples of what we want to achieve, and what currently happens, as an example. The yellow square is a XAML element that is inside a ScrollViewer, and the dots are the fingers and their movement.
1. Moving an element and panning the canvas when trying to zoom
What we do: We try to pinch the canvas and accidentally touch one element with one finger, and the canvas with the other. What we expect: To zoom the canvas. What happens: The element moves with one finger, the canvas pan with the other.
2. Moving an element when trying to pan
What we do: We try to pan the canvas with two fingers and accidentally touch one element with one finger, and the canvas with the other. What we expect: To pan the canvas. What happens: The element moves with one finger, the canvas pan with the other.
3. Moving two elements when trying to zoom
What we do: We try to pinch the canvas and accidentally touch one element with one finger, and another with the other finger. What we expect: To zoom the canvas. What happens: Both elements move with each finger.
4. Moving two elements at the same time
What we do: We try moving two elements at the same time with two different hands. What we expect: Both elements move with each finger. What happens: Both elements move with each finger. 👍
We don't want to break this interaction, if the fingers are too far apart, if should be registered as individual pointers and not as a two finger gesture.
It would be really helpful if we could detect two finger gestures and use it to pan and zoom the canvas, instead of moving elements.