6

Could you please let me know how can I recognize long press gesture in Xamarin Forms application?

This is my xaml page which i created referring to this thread: Xamarin.forms.DataGrid

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataGridSample_01"
xmlns:dg="clr-namespace:Xamarin.Forms.DataGrid;assembly=Xamarin.Forms.DataGrid"
x:Class="DataGridSample_01.MainPage">

 <ContentView BackgroundColor="White" Padding="20" >
  <dg:DataGrid ItemsSource="{Binding Data}" SelectionEnabled="True" RowHeight="70" HeaderHeight="50" BorderColor="#CCCCCC" HeaderBackground="#E0E6F8" ActiveRowColor="#8899AA">
     <dg:DataGrid.Columns>
     <dg:DataGridColumn Title="Logo" PropertyName="Logo" Width="50" SortingEnabled="False">
        <dg:DataGridColumn.CellTemplate>
           <DataTemplate>
              <Image Source="{Binding}" HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit" HeightRequest="60" />
           </DataTemplate>
        </dg:DataGridColumn.CellTemplate>
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Team" PropertyName="Name" Width="2*" >
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Win" PropertyName="Win" Width="2*">
        <dg:DataGridColumn.CellTemplate>
           <DataTemplate>
              <Picker x:Name="Fruits" Title="Fruits" HorizontalOptions="FillAndExpand">
                 <Picker.Items>
                    <x:String>Apple</x:String>
                    <x:String>Mango</x:String>
                    <x:String>PineApple</x:String>
                    <x:String>Orange</x:String>
                 </Picker.Items>
              </Picker>
           </DataTemplate>
        </dg:DataGridColumn.CellTemplate>
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Loose" PropertyName="Loose"  Width="1*">                    
     </dg:DataGridColumn>
     <dg:DataGridColumn PropertyName="Home">
        <dg:DataGridColumn.FormattedTitle>
           <FormattedString>
              <Span Text="Home" ForegroundColor="Black" FontSize="13" FontAttributes="Bold"/>
              <Span Text=" (win-loose)" ForegroundColor="#333333" FontSize="11" />
           </FormattedString>
        </dg:DataGridColumn.FormattedTitle>
     </dg:DataGridColumn>
     <dg:DataGrid.RowsBackgroundColorPalette>
        <dg:PaletteCollection>
           <Color>#FFFFFF</Color>
        </dg:PaletteCollection>
     </dg:DataGrid.RowsBackgroundColorPalette>
  </dg:DataGrid>
 </ContentView>
</ContentPage>

I want to add a Long Press Gesture recognizer on Image Control.I tried to do it referring to this StackOverflow Thread.But it doesn't seem to work.

I am very new to this. Any help is very much appreciated.

Cfun
  • 8,442
  • 4
  • 30
  • 62
Mars
  • 269
  • 1
  • 3
  • 22

2 Answers2

13

It is no longer required to define your own effect, since TouchEffect already exists in Xamarin Community Toolkit package (which is a package that gathers a lot of cool reusable/common controls, effects, behaviors, converters...).

xaml namespace:

 xmlns:xct="http://xamarin.com/schemas/2020/toolkit"

Sample of usage

You can set a duration of the long press required to trigger the command, or leave it by default = 500ms. In this example LongPressCommand will be fired/triggered after 2 seconds.

<Image Source="{Binding}" HorizontalOptions="Center" VerticalOptions="Center"
       Aspect="AspectFit" HeightRequest="60"
       xct:TouchEffect.LongPressCommand="{Binding LongPressCommand}"
       xct:TouchEffect.LongPressDuration="2000"/>
ICommand LongPressCommand = new Command(() =>
            {
                LongPressCount++;
                OnPropertyChanged(nameof(LongPressCount));
            });

Also, the same as CommandParameter you have an optional LongPressCommandParameter, where you can bind a custom parameter to your command.

Resource

Documentation (under work) https://learn.microsoft.com/en-us/xamarin/community-toolkit/

Repo https://github.com/xamarin/XamarinCommunityToolkit/

https://www.youtube.com/watch?v=BcFlZMhPmVk

Cfun
  • 8,442
  • 4
  • 30
  • 62
  • If you apply to a Picker control, you loose the hability to select items, any clue? – Caverna Jul 30 '22 at 20:33
  • 1
    Out of curiosity why would you apply a long press gesture to a picker? if you believe it is a bug you can always report it or open a discussion at the official repo. – Cfun Jul 30 '22 at 22:11
3

You can use Effect to add LongPressGestureRecognizer to any control.

in Forms ,creat a new shared Effect.

using System;
using System.Windows.Input;
using Xamarin.Forms;

namespace App15
{
  public class LongPressedEffect : RoutingEffect
  {
    public LongPressedEffect() : base("MyApp.LongPressedEffect")
    {

    }

    public static readonly BindableProperty CommandProperty = BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(LongPressedEffect), (object)null);
    public static ICommand GetCommand(BindableObject view)
    {

        //do something you want 
        Console.WriteLine("long press Gesture recognizer has been striked");


        return (ICommand)view.GetValue(CommandProperty);
    }

    public static void SetCommand(BindableObject view, ICommand value)
    {
        view.SetValue(CommandProperty, value);

    }


    public static readonly BindableProperty CommandParameterProperty = BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(LongPressedEffect), (object)null);
    public static object GetCommandParameter(BindableObject view)
    {

        return view.GetValue(CommandParameterProperty);
    }

    public static void SetCommandParameter(BindableObject view, object value)
    {
        view.SetValue(CommandParameterProperty, value);
    }
  }
}

in Android Project

using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using App15;
using App15.Droid;    

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(AndroidLongPressedEffect), "LongPressedEffect")]
namespace AndroidAppNamespace.Effects
{

  public class AndroidLongPressedEffect : PlatformEffect
  {
    private bool _attached;

    public static void Initialize() { }

    public AndroidLongPressedEffect()
    {
    }

    protected override void OnAttached()
    {
        //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time.
        if (!_attached)
        {
            if (Control != null)
            {
                Control.LongClickable = true;
                Control.LongClick += Control_LongClick;
            }
            else
            {
                Container.LongClickable = true;
                Container.LongClick += Control_LongClick;
            }
            _attached = true;
        }
    }


    // Invoke the command if there is one
    private void Control_LongClick(object sender, Android.Views.View.LongClickEventArgs e)
    {
        Console.WriteLine("Invoking long click command");
        var command = LongPressedEffect.GetCommand(Element);
        command?.Execute(LongPressedEffect.GetCommandParameter(Element));
    }


    protected override void OnDetached()
    {
        if (_attached)
        {
            if (Control != null)
            {
                Control.LongClickable = true;
                Control.LongClick -= Control_LongClick;
            }
            else
            {
                Container.LongClickable = true;
                Container.LongClick -= Control_LongClick;
            }
            _attached = false;
        }
    }
}

in iOS Project

using Foundation;
using UIKit;
using App15;
using App15.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(iOSLongPressedEffect), "LongPressedEffect")]
namespace App15.iOS
{
  public class iOSLongPressedEffect : PlatformEffect
  {
    private bool _attached;
    private readonly UILongPressGestureRecognizer _longPressRecognizer;

    public iOSLongPressedEffect()
    {
        _longPressRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
    }


    protected override void OnAttached()
    {
        //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time
        if (!_attached)
        {
            Container.AddGestureRecognizer(_longPressRecognizer);
            _attached = true;
        }
    }


    // Invoke the command if there is one       
    private void HandleLongClick(UILongPressGestureRecognizer sender)
    {
        if(sender.State==UIGestureRecognizerState.Began)
        {
            var command = LongPressedEffect.GetCommand(Element);
            command?.Execute(LongPressedEffect.GetCommandParameter(Element));
        }


    }

    protected override void OnDetached()
    {
        if (_attached)
        {
            Container.RemoveGestureRecognizer(_longPressRecognizer);
            _attached = false;
        }
    }

  }
}

Now,you can add LongPressGestureRecognizer to controls.Such as Label or Image.

<Label Text="Long Press Me!" local:LongPressedEffect.Command="{Binding ShowAlertCommand}" local:LongPressedEffect.CommandParameter="{Binding .}">
  <Label.Effects>
      <local:LongPressedEffect />
  </Label.Effects>
</Label>

<Image Source="{Binding}" local:LongPressedEffect.Command="{Binding ShowAlertCommand}" local:LongPressedEffect.CommandParameter="{Binding .}">
   <Image.Effects>
        <local:LongPressedEffect />
   </Image.Effects>
</Image>

For more detail about Effect you can refer here

Lucas Zhang
  • 18,630
  • 3
  • 12
  • 22
  • 11
    While its good to have this code in StackOverflow, please make sure that you **give credit to the original source** - its the right thing to do, and it is a legal requirement of SO, and copyright law. This appears to be a copy of Alex Dunn: [Xamarin Tip: Xamarin.Forms Long Press Effect](https://alexdunn.org/2017/12/27/xamarin-tip-xamarin-forms-long-press-effect/), from 2017. – ToolmakerSteve Jun 30 '19 at 20:29
  • 5
    Minor technical note: Of course, the end result isn't a "GestureRecognizer", it is an "Effect". So instead of saying "now you can add LongPressGestureRecognizer to controls", it would be more accurate to say "Now we can handle long press by adding a `LongPressedEffect` to any control." – ToolmakerSteve Jun 30 '19 at 20:44
  • 2
    Using this makes Tap gestures added in Android to not be detected, any ideas how to fix that? – Kikanye Nov 04 '19 at 04:08