Reputation: 1571
On my MainPage, I have a Stackpanel full of multicolored Rectangles, and they all start with Margin set to (0,5,0,5). I would like to allow the user to move these rectangles horizontally only. Since Rectangles do not have Mouse events, I use the Pointer to achieve this. The flow is: user taps on a Rectangle to select it, cursor changes to give user visual cue, user drags Rectangle left or right. (Note that the Stackpanel does have a vertical scrollviewer, if that matters). Here is my C# code:
private void Rectangle_FirstClick(object sender, EventArgs e)
{
// Give rectangle a white border to imply selection
Rectangle myControl = sender as Rectangle;
myControl.StrokeThickness = 1;
myControl.Stroke = new SolidColorBrush(Color.FromArgb(255, 240, 240, 240));
// Provide visual cue to mouse users by changing the pointer immediately
Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.SizeWestEast, 0);
// Handle mouse leaving/re-entering the track piece
myControl.PointerEntered += MyControl_PointerEntered;
myControl.PointerExited += MyControl_PointerExited;
// Handle the drag event
myControl.PointerPressed += MyControl_PointerPressed;
myControl.PointerReleased += MyControl_PointerReleased;
myControl.PointerMoved += MyControl_PointerMoved;
}
Here are the individual event handlers
bool PossibleDragStart = false;
Point InitialDragPoint = new Point(0, 0);
private void MyControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.Arrow, 0);
}
private void MyControl_PointerEntered(object sender, PointerRoutedEventArgs e)
{
Window.Current.CoreWindow.PointerCursor = new Windows.UI.Core.CoreCursor(Windows.UI.Core.CoreCursorType.SizeWestEast, 0);
}
private void MyControl_PointerPressed(object sender, PointerRoutedEventArgs e)
{
PossibleDragStart = true;
InitialDragPoint = e.GetCurrentPoint(sender as Rectangle).Position;
}
private void MyControl_PointerReleased(object sender, PointerRoutedEventArgs e)
{
PossibleDragStart = false;
}
private void MyControl_PointerMoved(object sender, PointerRoutedEventArgs e)
{
// If pointer pressed without release, and then moved, we are dragging
if (PossibleDragStart)
{
Point CurrentDragPoint = e.GetCurrentPoint(AudioTracksRightContainer).Position;
StatusBar.Text = CurrentDragPoint.X.ToString();
// Calculate drag offset by subtracting Current Position from Initial Position
double SegmentMargin = CurrentDragPoint.X - InitialDragPoint.X;
// Move the Rectangle with the pointer drag
Rectangle trackSegment = sender as Rectangle;
trackSegment.Margin = new Thickness(SegmentMargin, 5, 0, 5);
}
}
This code works great for the mouse, but when I try to use it for touch, I have to press-and-hold to initiate drag, and even then, the rectangle only moves a few units before staying put. I'm not sure why the behaviors are different.
Another issue with this code is that, if the rectangle is narrow enough such that when I drag quickly and the rectangle can't keep up with the cursor, it stops dragging when the cursor has left the rectangle boundary. A much smaller issue than the touch not working, but a little annoying nonetheless.
Upvotes: 0
Views: 573
Reputation: 21889
It sounds like the ScrollViewer is capturing the touch events to do its own scrolling. Insead of handling the manipulations manually you can use Xaml's manipulation engine to register for manipulation events. This is both easier to code and more efficient. It will work for touch and mouse by default.
<Rectangle Margin="5" Fill="Orange" Height="100" Width="200"
ManipulationMode="TranslateX"
ManipulationDelta="Rectangle_ManipulationDelta"
>
<Rectangle.RenderTransform>
<CompositeTransform />
</Rectangle.RenderTransform>
</Rectangle>
In the Rectangle_ManipulationDelta method translate the rectangle:
private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
UIElement elem = sender as UIElement;
CompositeTransform ct = elem.RenderTransform as CompositeTransform;
ct.TranslateX += e.Delta.Translation.X;
}
If you only want translations you could use a TranslateTransform instead of a CompositeTransform, or you could add in rotations and scaling.
See Quickstart: Touch input (XAML) for more on using gestures and manipulation events.
I discuss the ScrollViewer taking over pointer handling in my blog entry Where did all my gestures go? If you really want to handle the pointer events yourself I discuss how to disable the ScrollViewer during dragging. You can handle the case where the finger moves faster than the target by capturing the pointer. This isn't needed if you handle the manipulation events.
Upvotes: 1