mauiuitapgesturerecognizer

Label TapGestureRecognizer works with Tapped, but not with Command


I have followed James Montemagno's excellent .Net MAUI for Beginners series. In it, he uses a TapGestureRecognizer Command to go to a detail page for the item tapped. I downloaded his repo and tested and it works fine in VS 2022 v17.4.0 Preview 1.0.

I pretty much copied his code directly into mine and it doesn't work in my project for some reason. Now Tapped does work fine and goes to a new page, but when I use that method it wants me to pass in the view model, which I can't figure out. So I thought James' Command method might work better, but can't get it to even call the TapCommand code - nothing happens when clicking/tapping on the label.

So Edit Profile works. Edit Account does not. Here's the code:

XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CRUMSMobile.Views.Settings.UserSettings"
             xmlns:viewmodel="clr-namespace:CRUMSMobile.ViewModels.Settings"
             x:DataType="viewmodel:UserSettingsViewModel"
             Title="Settings">
    
    <VerticalStackLayout>
        <Label Text="Account Settings"
               FontSize="16"
               FontAttributes="Bold"
               TextColor="DarkGray"
               TextTransform="Uppercase"
               VerticalOptions="Start" 
               HorizontalOptions="Start" 
               Margin="20,20,0,30"/>

        <Label Text="Edit Account"
            HorizontalOptions="Start"
            FontSize="14"
            Margin="20,0,0,30">
            <Label.GestureRecognizers>
                <TapGestureRecognizer 
                        Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:UserSettingsViewModel}}, Path=TapCommand}"
                        CommandParameter="EditAccount"/>
            </Label.GestureRecognizers>
        </Label>

        <Label Text="Edit profile"
               HorizontalOptions="Start"
               FontSize="14"
               Margin="20,0,0,30">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Tapped="Edit_Profile_Tapped" />
            </Label.GestureRecognizers>
        </Label>
    </VerticalStackLayout>
</ContentPage>

Code behind:

public partial class UserSettings : ContentPage
{
    public UserSettings()
    {
        InitializeComponent();
    }

    private void Edit_Profile_Tapped(object sender, EventArgs e)
    {
        Navigation.PushAsync(new EditProfile());
    }
}

View Model:

public partial class UserSettingsViewModel : BaseViewModel
{
    public UserSettingsViewModel()
    {
    }

    [RelayCommand]
    async Task Tap(string s)
    {
        if (s == "EditAccount")
        {
            await Shell.Current.GoToAsync(nameof(EditAccount));
        }
    }
}

And here's the constructor for the EditAccount page:

public partial class EditAccount : ContentPage
{
    public EditAccount(EditAccountViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
        _ = GetUserAccount();
    }

[...]

Solution

  • As @GeraldVersluis suggested, you should use TapCommand firstly. Also, if you're using Shell to navigate through pages, don't forget to Register the routing for EditAccount page in AppShell.xaml.cs. Here's the detailed steps below for your reference:

    1. Install the CommunityToolkit.Mvvm package in your project.

    2. UserSettings.xaml:

        <VerticalStackLayout>
    
            <Label Text="Account Settings"
                   FontSize="16"
                   FontAttributes="Bold"
                   TextColor="DarkGray"
                   TextTransform="Uppercase"
                   VerticalOptions="Start"
                   HorizontalOptions="Start"
                   Margin="20,20,0,30"/>
            
            <Label Text="Edit Account"
                   HorizontalOptions="Start"
                   FontSize="14"
                   BackgroundColor="Red"
                   Margin="20,0,0,30">
                <Label.GestureRecognizers>
                    <TapGestureRecognizer
                         Command="{Binding TapCommand}"/>
                </Label.GestureRecognizers>
    
            </Label>
        </VerticalStackLayout>
    

    UserSettings.cs:

    public partial class UserSettings : ContentPage
    {
          public UserSettings()
          {
                InitializeComponent();
    
                BindingContext = new UserSettingsViewModel();
          }
    }
    

    3. ViewModel for the UserSetting Page:

    
        public partial class UserSettingsViewModel : ObservableObject 
        {
    
            [RelayCommand]
            async Task Tap()
            {
                await Shell.Current.GoToAsync(nameof(EditAccount));
            }
        }
    
    
    

    4. Register the routing:

    
          public AppShell() 
          {
                InitializeComponent();
    
                Routing.RegisterRoute(nameof(EditAccount), typeof(EditAccount));
          }