TapGestureRecogniser does not work inside a ListView ItemTemplate

MikeC 21 Reputation points
2021-02-14T00:04:56.53+00:00

I have an Android 9 Xamarin Forms app (no iOS) in which I'm binding a ListView to an ObservableCollection<Comp>. Inside each Comp instance is another ObservableCollection<CompEvent> (sporting events within a competition) and everything works just fine EXCEPT for TapGestureRecogniser inside the ViewCell which is totally ignored. The whole row is selected when I tap on one but the TapGesture command handler on the label simply never fires.

What I really want to do is to just have the tap select the whole row and the handler fire so I can open a DisplayAlert with some more info on the selected event (row) but putting the TapGestureRecogniser event on the Grid instead of the label also did not work.

Here's my XAML ItemTemplate, EventList definition and command handler from my ViewModel Can anyone explain why this doesn't work and/or help me get this working please ?

    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid HeightRequest="{Binding ViewHeight}" IsVisible="{Binding IsVisible}" >
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Label Text="{Binding EventNumber}" FontSize="Small" YAlign="Center" />
                    <Label Grid.Column="1" Text="{Binding Title}" FontSize="Small" YAlign="Center">
                        <Label.GestureRecognizers>
                            <TapGestureRecognizer Command="{Binding Path=BindingContext.ListViewTappedCommand, Source={x:Reference lvwEvents}}"
                                              CommandParameter="{Binding .}"/>
                        </Label.GestureRecognizers>
                    </Label>
                    <Label Grid.Column="2" Text="{Binding DisplayDate}" FontSize="Small" YAlign="Center" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>


public class EventList : ObservableCollection<CompEvent>, INotifyPropertyChanged
{
    public string Heading { get; set; }
    public DateTime NextEventData { get; set; }
    public string EventType { get; set; }
    public string NewsfeedURL { get; set; }

    public ObservableCollection<CompEvent> Events => this;

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs((propertyName)));
    }
}

public ICommand ListViewTappedCommand => new Command<EventList>((eventList) =>
{
    if (eventList.Count() > 0)
    {
        CompEvent compEvent = (CompEvent)eventList.ElementAt(0);
    }
});
Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,312 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. MikeC 21 Reputation points
    2021-02-14T02:14:05.007+00:00

    After more exploration I changed the code to use the event in the <ListView> XAML declaration rather than in the ViewCell and it fires but of course now I have the event handler in code behind rather than in the ViewModel - so how do I change the following so I can use a Command binding in the ViewModel?

    <ListView x:Name="lvwEvents"     
              ItemsSource="{Binding AllEvents}"              
              IsGroupingEnabled="True"
              GroupDisplayBinding="{Binding Heading}"
              HasUnevenRows="True"
              SelectionMode="Single"
              ItemSelected="lvwEvents_ItemSelected"    //want this in VewModel
              Margin="5">
    
    //Want this in ViewModel
    private async void lvwEvents_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        var type = sender.GetType();
        var evnt = (CompEvent)lvwEvents.SelectedItem;
        await DisplayAlert(evnt.CompName, evnt.Title + ": " + evnt.Details, "OK");
    }
    
    0 comments No comments

  2. Cole Xia (Shanghai Wicresoft Co,.Ltd.) 6,751 Reputation points
    2021-02-15T03:40:59.423+00:00

    Hello,

    Welcome to Microsoft Q&A!

    • Add GestureRecognizers on Grid . <Grid.GestureRecognizers>
      <TapGestureRecognizer Command="{Binding ListViewTappedCommand}"/>
      </Grid.GestureRecognizers>
    • Define the Command inside CompEvent class. public Command ListViewTappedCommand { get;set;} public CompEvent()
      { ListViewTappedCommand = new Command(()=> {
      //here you can get CompEvent itself
      });
      }

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments