Two-finger swipe gesture on GridView for UWP touch app - c#

I am trying to implement a two-finger swipe gesture for multi-selection of GridView. But I can't receive required pointer events for counting the number of fingers which are touching the screen. I am testing with Dell P2314T during development.
The order of pointer event fireing:
Theoretical:PointerPressed(pressed)=>PointerMoved(swiping)=>PointerReleased (released)
Actual:PointerPressed & PointerCaptureLost (when pressed but not released)
PS: The demo is removed.
Here is a snippet of my code, which obviously doesn't work because PointerMoved and PointerReleased don't fire:
class CustomGridView : GridView
{
List<uint> pointerPoint = new List<uint>();
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
(element as GridViewItem).AddHandler(PointerPressedEvent, new PointerEventHandler(OnPointerPressed), true);
(element as GridViewItem).PointerMoved += OnPointerMoved;
(element as GridViewItem).PointerReleased += OnPointerReleased;
base.PrepareContainerForItemOverride(element, item);
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
if (!pointerPoint.Contains(e.Pointer.PointerId))
{
Debug.WriteLine("add:" + e.Pointer.PointerId);
pointerPoint.Add(e.Pointer.PointerId);
}
}
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (pointerPoint.Count == 2)
{
Debug.WriteLine("two finger");
}
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (pointerPoint.Contains(e.Pointer.PointerId))
{
Debug.WriteLine("rem:" + e.Pointer.PointerId);
pointerPoint.Remove(e.Pointer.PointerId);
}
}
}

This is my solution:
Base on observation, ScrollViewer will capture the remaining pointer events.
ScrollViewer should be disabled and ongoing direct manipulation should be canceled when PointerPressed is fired.
XAML:
<GridView ScrollViewer.VerticalScrollMode="{x:Bind GridViewScrollMode}"/>
C#:
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
pointerPoints.Add(e.Pointer.PointerId);
if (PointerIds.Count == 2)
{
((sender as GridView).ContainerFromIndex(0) as GridViewItem).CancelDirectManipulations();
GridViewScrollMode = ScrollMode.Disabled;
}
}

Related

How to stop this flickering issue ,which occurs when the UI element is moved using touch?

I have a problem when I try to move the textblock using touch there is a flickering issue which does not occur when I do the same using mouse interaction. can someone help me here?
How to Stop this flickering issue?
public partial class MainWindow: Window
{
Canvas can = new Canvas() { Background=Brushes.White};
Grid grid = new Grid() { Height=150,Width=100,Background=Brushes.Yellow};
TextBlock textBlock = new TextBlock() { Text = "TextBlock Text" ,FontWeight=FontWeights.Bold };
Point point = new Point();
public MainWindow()
{
InitializeComponent();
grid.Children.Add(textBlock);
can.Children.Add(grid);
Canvas.SetLeft(grid, 0);
Canvas.SetTop(grid, 0);
textBlock.PreviewMouseDown += TextBlock_PreviewMouseDown;
textBlock.PreviewTouchDown += TextBlock_PreviewTouchDown;
can.PreviewMouseMove += Can_PreviewMouseMove;
can.PreviewTouchMove += Can_PreviewTouchMove;
m_grid.Children.Add(can);
}
private void TextBlock_PreviewTouchDown(object sender, TouchEventArgs e)
{
point = e.GetTouchPoint(this).Position;
}
private void TextBlock_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
point = e.GetPosition(this);
}
private void Can_PreviewTouchMove(object sender, TouchEventArgs e)
{
if (e.OriginalSource is TextBlock )
{
Canvas.SetLeft(grid, e.GetTouchPoint(this).Position.X - point.X);
Canvas.SetTop(grid, e.GetTouchPoint(this).Position.Y - point.Y);
}
}
private void Can_PreviewMouseMove(object sender, MouseEventArgs e)
{
if(e.OriginalSource is TextBlock && e.LeftButton==MouseButtonState.Pressed&&e.StylusDevice==null)
{
Canvas.SetLeft(grid, e.GetPosition(this).X - point.X);
Canvas.SetTop(grid, e.GetPosition(this).Y - point.Y);
}
}
}
I wasn't able to reproduce the flickering you're encountering, but I think it may be due to your implementation of drag/touch and drop.
The first problem I encountered with the code you posted was in the PreviewTouchDown and PreviewMouseDown event handlers. The code was setting the point to be relative to this - the Window - which when you first drag is okay, but after that any other drag attempt will immediately move the item up to the top/left corner.
To fix this, I edited the event handlers to set point to be relative to the grid so that the drag calculations would be correct on subsequent drags.
The second problem is that you are not capturing the mouse or touch device when dragging, which when dragging near the edge of the grid will cause the drag to stop. Capturing the mouse or touch will also make the drag much smoother.
To fix this, I added mouse and touch capture to the PreviewTouchDown and PreviewMouseDown event handlers, and added TouchUp and MouseUp event handlers that release the capture.
Here's the updated code in full:
public partial class MainWindow : Window
{
private Canvas can = new Canvas() { Background = Brushes.White };
private Grid grid = new Grid() { Height = 150, Width = 100, Background = Brushes.Yellow };
private TextBlock textBlock = new TextBlock() { Text = "TextBlock Text", FontWeight = FontWeights.Bold };
private Point point = new Point();
public MainWindow()
{
InitializeComponent();
grid.Children.Add(textBlock);
can.Children.Add(grid);
Canvas.SetLeft(grid, 0);
Canvas.SetTop(grid, 0);
textBlock.PreviewMouseDown += TextBlock_PreviewMouseDown;
textBlock.PreviewTouchDown += TextBlock_PreviewTouchDown;
textBlock.MouseUp += TextBlock_MouseUp;
textBlock.TouchUp += TextBlock_TouchUp;
can.PreviewMouseMove += Can_PreviewMouseMove;
can.PreviewTouchMove += Can_PreviewTouchMove;
RootGrid.Children.Add(can);
}
private void TextBlock_PreviewTouchDown(object sender, TouchEventArgs e)
{
point = e.GetTouchPoint(grid).Position;
e.TouchDevice.Capture(textBlock);
}
private void TextBlock_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
point = e.GetPosition(grid);
e.MouseDevice.Capture(textBlock);
}
private void TextBlock_TouchUp(object sender, TouchEventArgs e)
{
e.TouchDevice.Capture(null);
}
private void TextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
e.MouseDevice.Capture(null);
}
private void Can_PreviewTouchMove(object sender, TouchEventArgs e)
{
if (e.OriginalSource is TextBlock)
{
Canvas.SetLeft(grid, e.GetTouchPoint(this).Position.X - point.X);
Canvas.SetTop(grid, e.GetTouchPoint(this).Position.Y - point.Y);
}
}
private void Can_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.OriginalSource is TextBlock && e.LeftButton == MouseButtonState.Pressed && e.StylusDevice == null)
{
Canvas.SetLeft(grid, e.GetPosition(this).X - point.X);
Canvas.SetTop(grid, e.GetPosition(this).Y - point.Y);
}
}
}
I hope this is helpful.

MouseDown / MouseLeftButtonDown events not firing, MouseUp is?

Here's my code:
public AbilitiesController(Abilities page)
{
_page = page;
page.ScrollBar.MouseLeftButtonDown += MouseDown;
page.ScrollBar.MouseLeftButtonUp += MouseUp;
page.ScrollBar.MouseLeave += MouseLeave;
page.ScrollBar.MouseWheel += MouseWheel;
page.ScrollBar.MouseMove += MouseMove;
}
private void MouseMove(object sender, MouseEventArgs mouseEventArgs)
{
if (!_dragBound) return;
var newPos = mouseEventArgs.GetPosition(_page);
var dPos = newPos - _pos;
_page.ScrollBar.ScrollToHorizontalOffset(dPos.X);
_page.ScrollBar.ScrollToVerticalOffset(dPos.Y);
_pos = newPos;
Console.WriteLine("Moved");
}
private void MouseWheel(object sender, MouseWheelEventArgs mouseWheelEventArgs)
{
Console.WriteLine("MouseWheel");
}
private void MouseLeave(object sender, MouseEventArgs mouseEventArgs)
{
_dragBound = false;
Console.WriteLine("Left");
}
private void MouseUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
_dragBound = false;
Console.WriteLine("Mouse Up");
}
private void MouseDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
_dragBound = true;
Console.WriteLine("Click!");
}
Page is a Page, Scrollbar is a Scrollview.
I know my logic for moving the scrollbar probably isn't correct yet, but we aren't even getting that far yet.
For some odd reason the MouseDown event isn't firing whether I bind it to MouseDown or MouseLeftButtonDown.
However oddly enough the MouseUp event works no problem.
Which seems really odd because normally if one is broken, the other is too...
Using latest version of Visual Studio 2017 in a WPF project.
You might want to try 'PreviewMouseDown' instead of 'MouseDown' and same for all the other non-working mouse events, as they may already be being handled by whatever the base class of your 'Abilities' class is.

C# WPF Drag and Drop Button within StackPanel on a Canvas

This may be a basic question but I just started using WPF and I am having troubles trying to do a simple drag and drop.
I created this ToolboxButton class:
public class ToolboxButton : Button
{
private bool _isDragging = false;
private Point _startPoint;
public ToolboxButton(string content)
{
Content = content;
HorizontalAlignment = HorizontalAlignment.Stretch;
Height = 30;
Loaded += ToolboxButton_Loaded;
}
void ToolboxButton_Loaded(object sender, RoutedEventArgs e)
{
PreviewMouseLeftButtonDown += ToolboxButton_PreviewMouseLeftButtonDown;
PreviewMouseMove += ToolboxButton_PreviewMouseMove;
}
void ToolboxButton_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && !_isDragging)
{
Point position = e.GetPosition(null);
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
{
StartDrag(e);
}
}
}
void ToolboxButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(null);
}
private void StartDrag(MouseEventArgs e)
{
_isDragging = true;
DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
DragDrop.DoDragDrop(e.Source as ToolboxButton, data, DragDropEffects.Move);
_isDragging = false;
}
}
This button is added in a stackpanel like so:
ToolboxButton btnAddButton = new ToolboxButton("Button");
_toolboxView.Children.Add(btnAddButton); // _toolboxView is a stackpanel
And I have a Canvas with the following code:
public class DesignerView : Canvas
{
public DesignerView()
{
AllowDrop = true;
DragOver += DesignerView_DragOver;
Drop += DesignerView_Drop;
PreviewDragOver += DesignerView_PreviewDragOver;
}
void DesignerView_PreviewDragOver(object sender, DragEventArgs e)
{
MessageBox.Show("previewdragover");
}
void DesignerView_DragOver(object sender, DragEventArgs e)
{
MessageBox.Show("dragover");
if (!e.Data.GetDataPresent(typeof(ToolboxButton)))
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
if (e.Data.GetDataPresent(typeof(ToolboxButton)))
{
ToolboxButton droppedThingie = e.Data.GetData(typeof(ToolboxButton)) as ToolboxButton;
MessageBox.Show("You dropped: " + droppedThingie.Content);
}
}
public UIElement GetView()
{
return this;
}
}
Both Canvas and StackPanel are added in the main window like so:
Grid contentGrid = new Grid();
Content = contentGrid;
contentGrid.Children.Add(_toolboxView.GetView());
contentGrid.Children.Add(_designerView.GetView());
None of the MessageBoxes ever fire and I can't find out why. The cursor changes to the "Cannot pin", a dark circle with a diagonal line inside.
Am I missing something ? I want everything to be done in the code without XML.
Maybe I have to do something on the StackPanel but I tried the code of ToolboxButton there and it didn't work either.
As I can see you done all job, just DesignerView_drop left to correct.
use sender object to grab dragged object (in this example button)
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
Button btn = (Button)sender;
contentGrid.Children.Add(btn);
}

How to decide whether the user is performing a left or a right a swipe using CrossSlide(Gesture Recognizer) ? (WP8)

How can I determine if the user is performing a left or a right swipe? I found a tutorial showing me how to use the CrossSlide Event. The code I got from the tutorial:
Mainpage.xaml:
<Grid Name="LayoutRoot">
<TextBox Name="TxtGestureNotes"
Text="Hallo"
VerticalAlignment="Center"
HorizontalAlignment="Center">
</TextBox>
</Grid>
Mainpage.xaml.cs:
public sealed partial class MainPage : Page
{
GestureRecognizer gestureRecognizer = new GestureRecognizer();
Windows.UI.Xaml.UIElement element;
public MainPage()
{
this.InitializeComponent();
Page_Loaded();
}
public void GestureInputProcessor(Windows.UI.Input.GestureRecognizer gr, Windows.UI.Xaml.UIElement target) {
this.gestureRecognizer = gr;
//Targeted UI element to be performing gestures on it.
this.element = target;
//Enable gesture settings for Tap, CrossSlide
this.gestureRecognizer.GestureSettings = GestureSettings.Tap | GestureSettings.CrossSlide;
// set up pointer event handlers. these receive input events that are used by the gesture recognizer
this.element.PointerCanceled += OnPointerCanceled;
this.element.PointerPressed += OnPointerPressed;
this.element.PointerReleased += OnPointerReleased;
this.element.PointerMoved += OnPointerMoved;
// set up event handlers to respond to gesture recognizer
gestureRecognizer.Tapped += gestureRecognizer_Tapped;
//CrossSliding distance thresholds are disabled by default. Use CrossSlideThresholds to set these values.
Windows.UI.Input.CrossSlideThresholds cst = new Windows.UI.Input.CrossSlideThresholds();
cst.SelectionStart = 2;
cst.SpeedBumpStart = 3;
cst.SpeedBumpEnd = 4;
cst.RearrangeStart = 5;
gestureRecognizer.CrossSlideHorizontally = true;
gestureRecognizer.CrossSlideThresholds = cst;
gestureRecognizer.CrossSliding += gestureRecognizer_CrossSliding;
}
private void Page_Loaded() {
// For makig gestures operations on Grid named as 'LayoutRoot'
GestureInputProcessor(gestureRecognizer, LayoutRoot);
}
private void Page_Unloaded(object sender, RoutedEventArgs e) {
// Remove event handlers of gesture recognizers events
gestureRecognizer.Tapped -= gestureRecognizer_Tapped;
gestureRecognizer.CrossSliding -= gestureRecognizer_CrossSliding;
}
// Pointer Events
private void OnPointerCanceled(object sender, PointerRoutedEventArgs e) {
this.gestureRecognizer.CompleteGesture();
e.Handled = true;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e) {
// Route the events to the gesture recognizer
this.gestureRecognizer.ProcessDownEvent(e.GetCurrentPoint(this.element));
//Set the pointer capture to the element being interacterd with
this.element.CapturePointer(e.Pointer);
// Mark the event handled to prevent execution of default handlers
e.Handled = true;
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e) {
this.gestureRecognizer.ProcessUpEvent(e.GetCurrentPoint(this.element));
e.Handled = true;
}
private void OnPointerMoved(object sender, PointerRoutedEventArgs e) {
this.gestureRecognizer.ProcessMoveEvents(e.GetIntermediatePoints(this.element));
}
private void gestureRecognizer_Tapped(GestureRecognizer sender, TappedEventArgs args) {
TxtGestureNotes.Text = "Tap gesture recognized";
}
private void gestureRecognizer_CrossSliding(GestureRecognizer sender, CrossSlidingEventArgs args) {
TxtGestureNotes.Text = "Slide gesture recognized";
}
}
But how can i differentiate the swipe gesture such as right or left? Any help would be appreciated.
Try using the GestureService from Silverlight Toolkit in order to identify the Swiping Gesture.
how to get swipe in windows phone 7
Within the above sample try displaying something:
if (e.HorizontalVelocity < 0)
{
// Display something
MessageBox.Show("Swiped Right");
}
// User flicked towards right
if (e.HorizontalVelocity > 0)
{
// Display something
MessageBox.Show("Swiped Right");
}

C# DragDrop from toolStrip

I'm looking for a way to determine which item in a toolStrip that was dragged after a DragDrop event has occured, all I want to do is make a switch case with different cases for each item in the toolstrip but I cant seem to find a way of comparing them.
UPDATE: SHORT CODESAMPLE
private void toolStrip1_DragDrop(object sender, DragEventArgs e)
{
//Here I want something like a DoDragDrop() and send the specific item from the
//toolstrip..
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
//And here some way to determine which of the items was dragged
//(I'm not completely sure if I need a mouseUp event though..)
}
Hopefully a bit easier to get what I'm trying to do.
The events in your example don't look like the correct events to use.
Here is a working example from a ToolStrip that has 2 ToolStripButtons on it:
public Form1() {
InitializeComponent();
toolStripButton1.MouseDown += toolStripButton_MouseDown;
toolStripButton2.MouseDown += toolStripButton_MouseDown;
panel1.DragEnter += panel1_DragEnter;
panel1.DragDrop += panel1_DragDrop;
}
void toolStripButton_MouseDown(object sender, MouseEventArgs e) {
this.DoDragDrop(sender, DragDropEffects.Copy);
}
void panel1_DragEnter(object sender, DragEventArgs e) {
e.Effect = DragDropEffects.Copy;
}
void panel1_DragDrop(object sender, DragEventArgs e) {
ToolStripButton button = e.Data.GetData(typeof(ToolStripButton))
as ToolStripButton;
if (button != null) {
if (button.Equals(toolStripButton1)) {
MessageBox.Show("Dragged and dropped Button 1");
} else if (button.Equals(toolStripButton2)) {
MessageBox.Show("Dragged and dropped Button 2");
}
}
}

Categories