I'm creating a WinUI 3 User Control that -for sake of simplicity- can be described as glorified slider:
- Whenever user presses their left click (
PointerPressed
event), Pointer movement starts being tracked. - Whenever uses releases their left click (
PointerReleased
event), this tracking stops.
Sample XAML
<UserControl [...] >
<Border Name="MainArea"
PointerPressed="StartCapturing"
PointerReleased="StopCapturing"
PointerMoved="CaptureCoords"
[...] >
<!-- [...] -->
</Border>
</UserControl>
Sample C#
bool _isCapturing = false;
private void CalculateCoords(PointerRoutedEventArgs args){
// max distance is [w,h]. min distance is [0,0]
var h = MainArea.ActualHeight;
var w = MainArea.ActualWidth;
// Coordinates relative to the MainArea element;
var pos = args.GetCurrentPoint(MainArea).Position;
var (x, y) = (pos.X, pos.Y);
// clip 0% - 100%
x = x < 0 ? 0 : (x > w ? w : x);
y = y < 0 ? 0 : (y > h ? h : y);
// convert to percentages
var (x_perc, y_perc) = (x/w, y/h);
// Do stuff with the two percentages
}
public void StartCapturing(object? sender, PointerRoutedEventArgs args){
_isCapturing = true;
CalculateCoords(args);
}
public void CaptureCoords(object? sender, PointerRoutedEventArgs args){
if (!_isCapturing) return;
CalculateCoords(args);
}
public void StopCapturing(object? sender, PointerRoutedEventArgs args){
_isCapturing = false;
CalculateCoords(args);
}
This methodology works fine while the cursor is inside the control. The problem comes when the cursor leaves the element: Movement tracking stops and, if click is released outside of the bounding box, the capturing will continue once the mouse re-enters the bounding box, even without click pressed.
These problems where to be expected. To eliminate them, the only possible solutions I have thought of but don't know how to implement them, are:
- Force-Capture Mouse events, even when pointer exits the control
- Restrain mouse movement within control's bounding box
Is there a way to do any of these two things?
CodePudding user response:
You can use CapturePointer in StartCapturing
.
You typically capture the pointer because you want the current pointer action to initiate a behavior in your app. In this case you typically don't want other elements to handle any other events that come from that pointer's actions, until your behavior is either completed or is canceled by releasing the pointer capture. If a pointer is captured, only the element that has capture gets the pointer's input events, and other elements don't fire events even if the pointer moves into their bounds. For example, consider a UI that has two adjacent elements. Normally, if you moved the pointer from one element to the other, you'd first get PointerMoved events from the first element, and then from the second element. But if the first element has captured the pointer, then the first element continues to receive PointerMoved events even if the captured pointer leaves its bounds. Also, the second element doesn't fire PointerEntered events for a captured pointer when the captured pointer enters it.
public void StartCapturing(object sender, PointerRoutedEventArgs args)
{
_isCapturing = true;
CalculateCoords(args);
MainArea.CapturePointer(args.Pointer);
}